Fix execution group of NodeD
[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@:@GNTNODEDGROUP@"
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   if _confd_enabled; then
296       start ganeti-luxid
297   else
298       return 0
299   fi
300 }
301
302 # Stops the master role
303 stop_master() {
304   if _confd_enabled ; then
305       stop ganeti-luxid
306   fi
307   stop ganeti-rapi
308   stop ganeti-masterd
309 }
310
311 # Start all daemons
312 start_all() {
313   for i in $(list_start_daemons); do
314     local rc=0
315
316     # Try to start daemon
317     start $i || rc=$?
318
319     if ! errmsg=$(check_exitcode $rc); then
320       echo "$errmsg" >&2
321       return 1
322     fi
323   done
324
325   return 0
326 }
327
328 # Stop all daemons
329 stop_all() {
330   for i in $(list_stop_daemons); do
331     stop $i
332   done
333 }
334
335 # SIGHUP a process to force re-opening its logfiles
336 rotate_logs() {
337   if [[ "$#" -lt 1 ]]; then
338     echo 'Missing daemon name.' >&2
339     return 1
340   fi
341
342   local name="$1"; shift
343   local pidfile=$(_daemon_pidfile $name)
344   local daemonexec=$(_daemon_executable $name)
345
346   if type -p start-stop-daemon >/dev/null; then
347     start-stop-daemon --stop --signal HUP --quiet \
348       --oknodo --pidfile $pidfile
349   else
350     _ignore_error killproc \
351       -p $pidfile \
352       $daemonexec -HUP
353   fi
354 }
355
356 # SIGHUP all processes
357 rotate_all_logs() {
358   for i in $(list_stop_daemons); do
359     rotate_logs $i
360   done
361 }
362
363 # Reloads the SSH keys
364 reload_ssh_keys() {
365   @RPL_SSH_INITD_SCRIPT@ restart
366 }
367
368 # Read @SYSCONFDIR@/rc.d/init.d/functions if start-stop-daemon not available
369 if ! type -p start-stop-daemon >/dev/null && \
370    [[ -f @SYSCONFDIR@/rc.d/init.d/functions ]]; then
371   _ignore_error . @SYSCONFDIR@/rc.d/init.d/functions
372 fi
373
374 if [[ "$#" -lt 1 ]]; then
375   echo "Usage: $0 <action>" >&2
376   exit 1
377 fi
378
379 orig_action=$1; shift
380
381 if [[ "$orig_action" == *_* ]]; then
382   echo "Command must not contain underscores" >&2
383   exit 1
384 fi
385
386 # Replace all dashes (-) with underlines (_)
387 action=${orig_action//-/_}
388
389 # Is it a known function?
390 if ! declare -F "$action" >/dev/null 2>&1; then
391   echo "Unknown command: $orig_action" >&2
392   exit 1
393 fi
394
395 # Call handler function
396 $action "$@"