blob: 6af85c29e9a99fbc292772a54d4fd1f5a50f1ead [file] [log] [blame]
#!/bin/bash
#
# Copyright (C) 2009, 2011, 2012 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
@SHELL_ENV_INIT@
readonly defaults_file="$SYSCONFDIR/default/ganeti"
# This is a list of all daemons and the order in which they're started. The
# order is important as there are dependencies between them. On shutdown,
# they're stopped in reverse order.
DAEMONS=(
ganeti-noded
ganeti-confd
ganeti-wconfd
ganeti-rapi
ganeti-luxid
ganeti-kvmd
)
# This is the list of daemons that are loaded on demand; they should only be
# stopped, not started.
ON_DEMAND_DAEMONS=(
ganeti-metad
)
_mond_enabled() {
[[ "@CUSTOM_ENABLE_MOND@" == True ]]
}
if _mond_enabled; then
DAEMONS+=( ganeti-mond )
fi
# The full list of all daemons we know about
ALL_DAEMONS=( ${DAEMONS[@]} ${ON_DEMAND_DAEMONS[@]} )
NODED_ARGS=
CONFD_ARGS=
WCONFD_ARGS=
LUXID_ARGS=
RAPI_ARGS=
MOND_ARGS=
# Read defaults file if it exists
if [[ -s $defaults_file ]]; then
. $defaults_file
fi
# Meant to facilitate use utilities in /etc/rc.d/init.d/functions in case
# start-stop-daemon is not available.
_ignore_error() {
eval "$@" || :
}
_daemon_pidfile() {
echo "$RUN_DIR/$1.pid"
}
_daemon_executable() {
echo "@PREFIX@/sbin/$1"
}
_daemon_usergroup() {
case "$1" in
confd)
echo "@GNTCONFDUSER@:@GNTCONFDGROUP@"
;;
wconfd)
echo "@GNTWCONFDUSER@:@GNTWCONFDGROUP@"
;;
luxid)
echo "@GNTLUXIDUSER@:@GNTLUXIDGROUP@"
;;
rapi)
echo "@GNTRAPIUSER@:@GNTRAPIGROUP@"
;;
noded)
echo "@GNTNODEDUSER@:@GNTNODEDGROUP@"
;;
mond)
echo "@GNTMONDUSER@:@GNTMONDGROUP@"
;;
metad)
echo "@GNTMETADUSER@:@GNTMETADGROUP@"
;;
*)
echo "root:@GNTDAEMONSGROUP@"
;;
esac
}
# Specifies the additional capabilities needed by individual daemons
_daemon_caps() {
case "$1" in
metad)
echo "cap_net_bind_service=+ep"
;;
*)
echo ""
;;
esac
}
# Checks whether the local machine is part of a cluster
check_config() {
local server_pem=$DATA_DIR/server.pem
local fname
for fname in $server_pem; do
if [[ ! -f $fname ]]; then
echo "Missing configuration file $fname" >&2
return 1
fi
done
return 0
}
# Checks the exit code of a daemon
check_exitcode() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing exit code.' >&2
return 1
fi
local rc="$1"; shift
case "$rc" in
0) ;;
11)
echo "not master"
;;
*)
echo "exit code $rc"
return 1
;;
esac
return 0
}
# Checks if we should use systemctl to start/stop daemons
use_systemctl() {
# Is systemd running as PID 1?
[ -d /run/systemd/system ] || return 1
type -p systemctl >/dev/null || return 1
# Does systemd know about Ganeti at all?
loadstate="$(systemctl show -pLoadState ganeti.target)"
if [ "$loadstate" = "LoadState=loaded" ]; then
return 0
fi
return 1
}
# Prints path to PID file for a daemon.
daemon_pidfile() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing daemon name.' >&2
return 1
fi
local name="$1"; shift
_daemon_pidfile $name
}
# Prints path to daemon executable.
daemon_executable() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing daemon name.' >&2
return 1
fi
local name="$1"; shift
_daemon_executable $name
}
# Prints a list of all daemons in the order in which they should be started
list_start_daemons() {
local name
for name in "${DAEMONS[@]}"; do
echo "$name"
done
}
# Prints a list of all daemons in the order in which they should be stopped
list_stop_daemons() {
for name in "${ALL_DAEMONS[@]}"; do
echo "$name"
done | tac
}
# Checks whether a daemon name is known
is_daemon_name() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing daemon name.' >&2
return 1
fi
local name="$1"; shift
for i in "${ALL_DAEMONS[@]}"; do
if [[ "$i" == "$name" ]]; then
return 0
fi
done
echo "Unknown daemon name '$name'" >&2
return 1
}
# Checks whether daemon is running
check() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing daemon name.' >&2
return 1
fi
local name="$1"; shift
local pidfile=$(_daemon_pidfile $name)
local daemonexec=$(_daemon_executable $name)
if use_systemctl; then
activestate="$(systemctl show -pActiveState "${name}.service")"
if [ "$activestate" = "ActiveState=active" ]; then
return 0
else
return 1
fi
elif type -p start-stop-daemon >/dev/null; then
start-stop-daemon --stop --signal 0 --quiet \
--pidfile $pidfile
else
_ignore_error status \
-p $pidfile \
$daemonexec
fi
}
# Starts a daemon
start() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing daemon name.' >&2
return 1
fi
local name="$1"; shift
# Convert daemon name to uppercase after removing "ganeti-" prefix
local plain_name=${name#ganeti-}
local ucname=$(tr a-z A-Z <<<$plain_name)
local pidfile=$(_daemon_pidfile $name)
local usergroup=$(_daemon_usergroup $plain_name)
local daemonexec=$(_daemon_executable $name)
if use_systemctl; then
systemctl start "${name}.service"
return $?
fi
# Read $<daemon>_ARGS and $EXTRA_<daemon>_ARGS
eval local args="\"\$${ucname}_ARGS \$EXTRA_${ucname}_ARGS\""
@PKGLIBDIR@/ensure-dirs
# Grant capabilities to daemons that need them
local daemoncaps=$(_daemon_caps $plain_name)
if [[ "$daemoncaps" != "" ]]; then
if type -p setcap >/dev/null; then
setcap $daemoncaps $(readlink -f $daemonexec)
else
echo "setcap missing, could not set capabilities for $name." >&2
return 1
fi
fi
if type -p start-stop-daemon >/dev/null; then
start-stop-daemon --start --quiet --oknodo \
--pidfile $pidfile \
--startas $daemonexec \
--chuid $usergroup \
-- $args "$@"
else
# TODO: Find a way to start daemon with a group, until then the group must
# be removed
_ignore_error daemon \
--pidfile $pidfile \
--user ${usergroup%:*} \
$daemonexec $args "$@"
fi
}
# Stops a daemon
stop() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing daemon name.' >&2
return 1
fi
local name="$1"; shift
local pidfile=$(_daemon_pidfile $name)
if use_systemctl; then
systemctl stop "${name}.service"
elif type -p start-stop-daemon >/dev/null; then
start-stop-daemon --stop --quiet --oknodo --retry 30 \
--pidfile $pidfile
else
_ignore_error killproc -p $pidfile $name
fi
}
# Starts a daemon if it's not yet running
check_and_start() {
local name="$1"
if ! check $name; then
if use_systemctl; then
echo "${name} supervised by systemd but not running, will not restart."
return 1
fi
start $name
fi
}
# Starts the master role
start_master() {
if use_systemctl; then
systemctl start ganeti-master.target
else
start ganeti-wconfd
start ganeti-rapi
start ganeti-luxid
fi
}
# Stops the master role
stop_master() {
if use_systemctl; then
systemctl stop ganeti-master.target
else
stop ganeti-luxid
stop ganeti-rapi
stop ganeti-wconfd
fi
}
# Start all daemons
start_all() {
use_systemctl && systemctl start ganeti.target
# Fall through so that we detect any errors.
for i in $(list_start_daemons); do
local rc=0
# Try to start daemon
start $i || rc=$?
if ! errmsg=$(check_exitcode $rc); then
echo "$errmsg" >&2
return 1
fi
done
return 0
}
# Stop all daemons
stop_all() {
if use_systemctl; then
systemctl stop ganeti.target
else
for i in $(list_stop_daemons); do
stop $i
done
fi
}
# SIGHUP a process to force re-opening its logfiles
rotate_logs() {
if [[ "$#" -lt 1 ]]; then
echo 'Missing daemon name.' >&2
return 1
fi
local name="$1"; shift
local pidfile=$(_daemon_pidfile $name)
local daemonexec=$(_daemon_executable $name)
if type -p start-stop-daemon >/dev/null; then
start-stop-daemon --stop --signal HUP --quiet \
--oknodo --pidfile $pidfile
else
_ignore_error killproc \
-p $pidfile \
$daemonexec -HUP
fi
}
# SIGHUP all processes
rotate_all_logs() {
for i in $(list_stop_daemons); do
rotate_logs $i
done
}
# Reloads the SSH keys
reload_ssh_keys() {
@RPL_SSH_INITD_SCRIPT@ restart
}
# Read @SYSCONFDIR@/rc.d/init.d/functions if start-stop-daemon not available
if ! type -p start-stop-daemon >/dev/null && \
[[ -f @SYSCONFDIR@/rc.d/init.d/functions ]]; then
_ignore_error . @SYSCONFDIR@/rc.d/init.d/functions
fi
if [[ "$#" -lt 1 ]]; then
echo "Usage: $0 <action>" >&2
exit 1
fi
orig_action=$1; shift
if [[ "$orig_action" == *_* ]]; then
echo "Command must not contain underscores" >&2
exit 1
fi
# Replace all dashes (-) with underlines (_)
action=${orig_action//-/_}
# Is it a known function?
if ! declare -F "$action" >/dev/null 2>&1; then
echo "Unknown command: $orig_action" >&2
exit 1
fi
# Call handler function
$action "$@"