| #!/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 "$@" |