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