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