44c39a902280485c10c4c9cbe32dea69feed3c4b
[ganeti-github.git] / daemons / daemon-util.in
1 #!/bin/bash
2 #
3
4 # Copyright (C) 2009, 2011, 2012 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21 set -e
22
23 @SHELL_ENV_INIT@
24
25 readonly defaults_file="$SYSCONFDIR/default/ganeti"
26
27 # This is a list of all daemons and the order in which they're started. The
28 # order is important as there are dependencies between them. On shutdown,
29 # they're stopped in reverse order.
30 DAEMONS=(
31   ganeti-noded
32   ganeti-masterd
33   ganeti-rapi
34   )
35
36 _confd_enabled() {
37   [[ "@CUSTOM_ENABLE_CONFD@" == True ]]
38 }
39
40 if _confd_enabled; then
41   DAEMONS+=( ganeti-confd )
42   DAEMONS+=( ganeti-luxid )
43 fi
44
45 _mond_enabled() {
46   [[ "@CUSTOM_ENABLE_MOND@" == True ]]
47 }
48
49 if _mond_enabled; then
50   DAEMONS+=( ganeti-mond )
51 fi
52
53 NODED_ARGS=
54 MASTERD_ARGS=
55 CONFD_ARGS=
56 LUXID_ARGS=
57 RAPI_ARGS=
58 MOND_ARGS=
59
60 # Read defaults file if it exists
61 if [[ -s $defaults_file ]]; then
62   . $defaults_file
63 fi
64
65 # Meant to facilitate use utilities in /etc/rc.d/init.d/functions in case
66 # start-stop-daemon is not available.
67 _ignore_error() {
68   eval "$@" || :
69 }
70
71 _daemon_pidfile() {
72   echo "$RUN_DIR/$1.pid"
73 }
74
75 _daemon_executable() {
76   echo "@PREFIX@/sbin/$1"
77 }
78
79 _daemon_usergroup() {
80   case "$1" in
81     masterd)
82       echo "@GNTMASTERUSER@:@GNTMASTERDGROUP@"
83       ;;
84     confd)
85       echo "@GNTCONFDUSER@:@GNTCONFDGROUP@"
86       ;;
87     luxid)
88       echo "@GNTLUXIDUSER@:@GNTLUXIDGROUP@"
89       ;;
90     rapi)
91       echo "@GNTRAPIUSER@:@GNTRAPIGROUP@"
92       ;;
93     noded)
94       echo "@GNTNODEDUSER@:@GNTDAEMONSGROUP@"
95       ;;
96     mond)
97       echo "@GNTMONDUSER@:@GNTMONDGROUP@"
98       ;;
99     *)
100       echo "root:@GNTDAEMONSGROUP@"
101       ;;
102   esac
103 }
104
105 # Checks whether the local machine is part of a cluster
106 check_config() {
107   local server_pem=$DATA_DIR/server.pem
108   local fname
109
110   for fname in $server_pem; do
111     if [[ ! -f $fname ]]; then
112       echo "Missing configuration file $fname" >&2
113       return 1
114     fi
115   done
116
117   return 0
118 }
119
120 # Checks the exit code of a daemon
121 check_exitcode() {
122   if [[ "$#" -lt 1 ]]; then
123     echo 'Missing exit code.' >&2
124     return 1
125   fi
126
127   local rc="$1"; shift
128
129   case "$rc" in
130     0) ;;
131     11)
132       echo "not master"
133     ;;
134     *)
135       echo "exit code $rc"
136       return 1
137     ;;
138   esac
139
140   return 0
141 }
142
143 # Prints path to PID file for a daemon.
144 daemon_pidfile() {
145   if [[ "$#" -lt 1 ]]; then
146     echo 'Missing daemon name.' >&2
147     return 1
148   fi
149
150   local name="$1"; shift
151
152   _daemon_pidfile $name
153 }
154
155 # Prints path to daemon executable.
156 daemon_executable() {
157   if [[ "$#" -lt 1 ]]; then
158     echo 'Missing daemon name.' >&2
159     return 1
160   fi
161
162   local name="$1"; shift
163
164   _daemon_executable $name
165 }
166
167 # Prints a list of all daemons in the order in which they should be started
168 list_start_daemons() {
169   local name
170
171   for name in "${DAEMONS[@]}"; do
172     echo "$name"
173   done
174 }
175
176 # Prints a list of all daemons in the order in which they should be stopped
177 list_stop_daemons() {
178   list_start_daemons | tac
179 }
180
181 # Checks whether a daemon name is known
182 is_daemon_name() {
183   if [[ "$#" -lt 1 ]]; then
184     echo 'Missing daemon name.' >&2
185     return 1
186   fi
187
188   local name="$1"; shift
189
190   for i in "${DAEMONS[@]}"; do
191     if [[ "$i" == "$name" ]]; then
192       return 0
193     fi
194   done
195
196   echo "Unknown daemon name '$name'" >&2
197   return 1
198 }
199
200 # Checks whether daemon is running
201 check() {
202   if [[ "$#" -lt 1 ]]; then
203     echo 'Missing daemon name.' >&2
204     return 1
205   fi
206
207   local name="$1"; shift
208   local pidfile=$(_daemon_pidfile $name)
209   local daemonexec=$(_daemon_executable $name)
210
211   if type -p start-stop-daemon >/dev/null; then
212     start-stop-daemon --stop --signal 0 --quiet \
213       --pidfile $pidfile
214   else
215     _ignore_error status \
216       -p $pidfile \
217       $daemonexec
218   fi
219 }
220
221 # Starts a daemon
222 start() {
223   if [[ "$#" -lt 1 ]]; then
224     echo 'Missing daemon name.' >&2
225     return 1
226   fi
227
228   local name="$1"; shift
229   # Convert daemon name to uppercase after removing "ganeti-" prefix
230   local plain_name=${name#ganeti-}
231   local ucname=$(tr a-z A-Z <<<$plain_name)
232   local pidfile=$(_daemon_pidfile $name)
233   local usergroup=$(_daemon_usergroup $plain_name)
234   local daemonexec=$(_daemon_executable $name)
235
236   if ( [[ "$name" == ganeti-confd ]] || [[ "$name" == ganeti-luxid ]] ) \
237       && ! _confd_enabled; then
238     echo 'ganeti-confd disabled at build time' >&2
239     return 1
240   fi
241
242   # Read $<daemon>_ARGS and $EXTRA_<daemon>_ARGS
243   eval local args="\"\$${ucname}_ARGS \$EXTRA_${ucname}_ARGS\""
244
245   @PKGLIBDIR@/ensure-dirs
246
247   if type -p start-stop-daemon >/dev/null; then
248     start-stop-daemon --start --quiet --oknodo \
249       --pidfile $pidfile \
250       --startas $daemonexec \
251       --chuid $usergroup \
252       -- $args "$@"
253   else
254     # TODO: Find a way to start daemon with a group, until then the group must
255     # be removed
256     _ignore_error daemon \
257       --pidfile $pidfile \
258       --user ${usergroup%:*} \
259       $daemonexec $args "$@"
260   fi
261
262 }
263
264 # Stops a daemon
265 stop() {
266   if [[ "$#" -lt 1 ]]; then
267     echo 'Missing daemon name.' >&2
268     return 1
269   fi
270
271   local name="$1"; shift
272   local pidfile=$(_daemon_pidfile $name)
273
274   if type -p start-stop-daemon >/dev/null; then
275     start-stop-daemon --stop --quiet --oknodo --retry 30 \
276       --pidfile $pidfile
277   else
278     _ignore_error killproc -p $pidfile $name
279   fi
280 }
281
282 # Starts a daemon if it's not yet running
283 check_and_start() {
284   local name="$1"
285
286   if ! check $name; then
287     start $name
288   fi
289 }
290
291 # Starts the master role
292 start_master() {
293   start ganeti-masterd
294   start ganeti-rapi
295 }
296
297 # Stops the master role
298 stop_master() {
299   stop ganeti-rapi
300   stop ganeti-masterd
301 }
302
303 # Start all daemons
304 start_all() {
305   for i in $(list_start_daemons); do
306     local rc=0
307
308     # Try to start daemon
309     start $i || rc=$?
310
311     if ! errmsg=$(check_exitcode $rc); then
312       echo "$errmsg" >&2
313       return 1
314     fi
315   done
316
317   return 0
318 }
319
320 # Stop all daemons
321 stop_all() {
322   for i in $(list_stop_daemons); do
323     stop $i
324   done
325 }
326
327 # SIGHUP a process to force re-opening its logfiles
328 rotate_logs() {
329   if [[ "$#" -lt 1 ]]; then
330     echo 'Missing daemon name.' >&2
331     return 1
332   fi
333
334   local name="$1"; shift
335   local pidfile=$(_daemon_pidfile $name)
336   local daemonexec=$(_daemon_executable $name)
337
338   if type -p start-stop-daemon >/dev/null; then
339     start-stop-daemon --stop --signal HUP --quiet \
340       --oknodo --pidfile $pidfile
341   else
342     _ignore_error killproc \
343       -p $pidfile \
344       $daemonexec -HUP
345   fi
346 }
347
348 # SIGHUP all processes
349 rotate_all_logs() {
350   for i in $(list_stop_daemons); do
351     rotate_logs $i
352   done
353 }
354
355 # Reloads the SSH keys
356 reload_ssh_keys() {
357   @RPL_SSH_INITD_SCRIPT@ restart
358 }
359
360 # Read @SYSCONFDIR@/rc.d/init.d/functions if start-stop-daemon not available
361 if ! type -p start-stop-daemon >/dev/null && \
362    [[ -f @SYSCONFDIR@/rc.d/init.d/functions ]]; then
363   _ignore_error . @SYSCONFDIR@/rc.d/init.d/functions
364 fi
365
366 if [[ "$#" -lt 1 ]]; then
367   echo "Usage: $0 <action>" >&2
368   exit 1
369 fi
370
371 orig_action=$1; shift
372
373 if [[ "$orig_action" == *_* ]]; then
374   echo "Command must not contain underscores" >&2
375   exit 1
376 fi
377
378 # Replace all dashes (-) with underlines (_)
379 action=${orig_action//-/_}
380
381 # Is it a known function?
382 if ! declare -F "$action" >/dev/null 2>&1; then
383   echo "Unknown command: $orig_action" >&2
384   exit 1
385 fi
386
387 # Call handler function
388 $action "$@"