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