ctdb: Remove an unnecessary cast
[vlendec/samba-autobuild/.git] / ctdb / tools / onnode
index e7317b75f300cc7bb4a8c61fb37028d3d38a8563..f04d33f9c3f66181a8d1b141491921b61ec2e63d 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 
 # Run commands on CTDB nodes.
 
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
-   
+
 # This program is distributed in the hope that it will be useful,
 # but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
-   
+
 # You should have received a copy of the GNU General Public License
 # along with this program; if not, see <http://www.gnu.org/licenses/>.
 
@@ -31,10 +31,9 @@ usage ()
 Usage: onnode [OPTION] ... <NODES> <COMMAND> ...
   options:
     -c          Run in current working directory on specified nodes.
-    -f          Specify nodes file, overrides CTDB_NODES_FILE.
+    -f          Specify nodes file, overriding default.
     -i          Keep standard input open - the default is to close it.
     -n          Allow nodes to be specified by name.
-    -o <prefix> Save standard output from each node to file <prefix>.<ip>
     -p          Run command in parallel on specified nodes.
     -P          Push given files to nodes instead of running commands.
     -q          Do not print node addresses (overrides -v).
@@ -57,10 +56,10 @@ invalid_nodespec ()
 
 # Defaults.
 current=false
+ctdb_nodes_file=""
 parallel=false
 verbose=false
 quiet=false
-prefix=""
 names_ok=false
 push=false
 stdin=false
@@ -69,52 +68,45 @@ if [ -z "$CTDB_BASE" ] ; then
     CTDB_BASE="/usr/local/etc/ctdb"
 fi
 
-. "${CTDB_BASE}/functions"
-loadconfig "ctdb"
-
 parse_options ()
 {
-    # $POSIXLY_CORRECT means that the command passed to onnode can
-    # take options and getopt won't reorder things to make them
-    # options ot onnode.
-    local temp
-    # Not on the previous line - local returns 0!
-    temp=$(POSIXLY_CORRECT=1 getopt -n "$prog" -o "cf:hno:pqvPi" -l help -- "$@")
-
-    [ $? != 0 ] && usage
-
-    eval set -- "$temp"
-
-    while true ; do
-       case "$1" in
-           -c) current=true ; shift ;;
-           -f) CTDB_NODES_FILE="$2" ; shift 2 ;;
-           -n) names_ok=true ; shift ;;
-           -o) prefix="$2" ; shift 2 ;;
-           -p) parallel=true ; shift ;;
-           -q) quiet=true ; shift ;;
-           -v) verbose=true ; shift ;;
-           -P) push=true ; shift ;;
-           -i) stdin=true ; shift ;;
-           --) shift ; break ;;
-           -h|--help|*) usage ;; # Shouldn't happen, so this is reasonable.
-       esac
-    done
-
-    [ $# -lt 2 ] && usage
-
-    nodespec="$1" ; shift
-    command="$*"
+       local opt
+
+       while getopts "cf:hnpqvPi?" opt ; do
+               case "$opt" in
+               c) current=true ;;
+               f) ctdb_nodes_file="$OPTARG" ;;
+               n) names_ok=true ;;
+               p) parallel=true ;;
+               q) quiet=true ;;
+               v) verbose=true ;;
+               P) push=true ;;
+               i) stdin=true ;;
+               \?|h) usage ;;
+               esac
+       done
+       shift $((OPTIND - 1))
+
+       if [ $# -lt 2 ] ; then
+               usage
+       fi
+
+       nodespec="$1" ; shift
+       command="$*"
 }
 
 echo_nth ()
 {
     local n="$1" ; shift
 
-    shift "$n"
-    local node="$1"
+    # Note that this is 0-based
+    local node=""
+    if [ "$n" -le $# ] ; then
+           shift "$n"
+           node="$1"
+    fi
 
-    if [ -n "$node" -a "$node" != "#DEAD" ] ; then
+    if [ -n "$node" ] && [ "$node" != "#DEAD" ] ; then
        echo "$node"
     else
        echo "${prog}: \"node ${n}\" does not exist" >&2
@@ -147,6 +139,8 @@ get_nodes_with_status ()
 
     if [ -z "$ctdb_status_output" ] ; then
        ctdb_status_output=$(ctdb -X status 2>&1)
+       # No! Checking the exit code afterwards is actually clearer...
+       # shellcheck disable=SC2181
        if [ $? -ne 0 ] ; then
            echo "${prog}: unable to get status of CTDB nodes" >&2
            echo "$ctdb_status_output" >&2
@@ -154,13 +148,13 @@ get_nodes_with_status ()
        fi
        local nl="
 "
-       ctdb_status_output="${ctdb_status_output#*${nl}}"
+       ctdb_status_output="${ctdb_status_output#*"${nl}"}"
     fi
 
     (
        local i
        IFS="${IFS}|"
-       while IFS="" read i ; do
+       while IFS="" read -r i ; do
 
            # Intentional word splitting
            # shellcheck disable=SC2086
@@ -199,9 +193,9 @@ get_any_available_node ()
     # We do a recursive onnode to find which nodes are up and running.
     local out line
     out=$("$0" -pq all ctdb pnn 2>&1)
-    while read line ; do 
-       local pnn="${line#PNN:}"
-       if [ "$pnn" != "$line" ] ; then
+    while read -r line ; do
+       if [[ "$line" =~ ^[0-9]+$ ]] ; then
+           local pnn="$line"
            # Intentional multi-word expansion
            # shellcheck disable=SC2086
            echo_nth "$pnn" $all_nodes
@@ -214,97 +208,67 @@ get_any_available_node ()
 
 get_nodes ()
 {
-    local all_nodes
+       local all_nodes
 
-    if [ -n "$CTDB_NODES_SOCKETS" ] ; then 
-       all_nodes="$CTDB_NODES_SOCKETS"
-    else
        local f="${CTDB_BASE}/nodes"
-       if [ -n "$CTDB_NODES_FILE" ] ; then
-           f="$CTDB_NODES_FILE"
-           if [ ! -e "$f" -a "${f#/}" = "$f" ] ; then
-               # $f is relative, try in $CTDB_BASE
-               f="${CTDB_BASE}/${f}"
-           fi
-       elif [ -n "$CTDB_NODES" ] ; then
-           f="$CTDB_NODES"
+       if [ -n "$ctdb_nodes_file" ] ; then
+               f="$ctdb_nodes_file"
+               if [ ! -e "$f" ] && [ "${f#/}" = "$f" ] ; then
+                       # $f is relative, try in $CTDB_BASE
+                       f="${CTDB_BASE}/${f}"
+               fi
        fi
 
        if [ ! -r "$f" ] ; then
-           echo "${prog}: unable to open nodes file  \"${f}\"" >&2
-           exit 1
+               echo "${prog}: unable to open nodes file  \"${f}\"" >&2
+               exit 1
        fi
 
        all_nodes=$(sed -e 's@#.*@@g' -e 's@ *@@g' -e 's@^$@#DEAD@' "$f")
-    fi
-
-    local nodes=""
-    local n
-    for n in $(parse_nodespec "$1") ; do
-       [ $? != 0 ] && exit 1  # Required to catch exit in above subshell.
-       case "$n" in
-           all)
-               echo "${all_nodes//#DEAD/}"
-               ;;
-           any)
-               get_any_available_node "$all_nodes" || exit 1
-               ;;
-           ok|healthy) 
-               get_nodes_with_status "$all_nodes" "healthy" || exit 1
-               ;;
-           con|connected) 
-               get_nodes_with_status "$all_nodes" "connected" || exit 1
-               ;;
-           [0-9]|[0-9][0-9]|[0-9][0-9][0-9])
-               # Intentional multi-word expansion
-               # shellcheck disable=SC2086
-               echo_nth "$n" $all_nodes
-               ;;
-           *)
-               $names_ok || invalid_nodespec
-               echo "$n"
-       esac
-    done
-}
-
-push()
-{
-    local host="$1"
-    local files="$2"
-
-    local f
-    for f in $files ; do
-        $verbose && echo "Pushing $f"
-        case "$f" in
-           /*) rsync "$f" "[${host}]:${f}" ;;
-           *)  rsync "${PWD}/${f}" "[${host}]:${PWD}/${f}" ;;
-       esac
-    done
-}
-
-fakessh ()
-{
-    CTDB_SOCKET="$1" sh -c "$2" 3>/dev/null
-}
 
-stdout_filter ()
-{
-    if [ -n "$prefix" ] ; then
-       cat >"${prefix}.${n//\//_}"
-    elif $verbose && $parallel ; then
-       sed -e "s@^@[$n] @"
-    else
-       cat
-    fi
+       local n nodes
+       nodes=$(parse_nodespec "$1") || exit $?
+       for n in $nodes ; do
+               case "$n" in
+               all)
+                       echo "${all_nodes//#DEAD/}"
+                       ;;
+               any)
+                       get_any_available_node "$all_nodes" || exit 1
+                       ;;
+               ok|healthy)
+                       get_nodes_with_status "$all_nodes" "healthy" || exit 1
+                       ;;
+               con|connected)
+                       get_nodes_with_status "$all_nodes" "connected" || exit 1
+                       ;;
+               [0-9]|[0-9][0-9]|[0-9][0-9][0-9])
+                       # Intentional multi-word expansion
+                       # shellcheck disable=SC2086
+                       echo_nth "$n" $all_nodes
+                       ;;
+               *)
+                       $names_ok || invalid_nodespec
+                       echo "$n"
+               esac
+       done
 }
 
-stderr_filter ()
+# shellcheck disable=SC2317
+# push() called indirectly via $ONNODE_SSH
+push ()
 {
-    if $verbose && $parallel ; then
-       sed -e "s@^@[$n] @"
-    else
-       cat
-    fi
+       local host="$1"
+       local files="$2"
+
+       local f
+       for f in $files ; do
+               $verbose && echo "Pushing $f"
+               case "$f" in
+               /*) rsync "$f" "[${host}]:${f}" ;;
+               *)  rsync "${PWD}/${f}" "[${host}]:${PWD}/${f}" ;;
+               esac
+       done
 }
 
 ######################################################################
@@ -313,32 +277,25 @@ parse_options "$@"
 
 ssh_opts=
 if $push ; then
-    SSH=push
-    EXTRA_SSH_OPTS=""
+       if [ -n "$ONNODE_SSH" ] ; then
+               export RSYNC_RSH="$ONNODE_SSH"
+       fi
+       ONNODE_SSH=push
 else
-    $current && command="cd $PWD && $command"
+       $current && command="cd $PWD && $command"
 
-    if [ -n "$CTDB_NODES_SOCKETS" ] ; then
-       SSH=fakessh
-       EXTRA_SSH_OPTS=""
-    else 
        # Could "2>/dev/null || true" but want to see errors from typos in file.
        [ -r "${CTDB_BASE}/onnode.conf" ] && . "${CTDB_BASE}/onnode.conf"
-       [ -n "$SSH" ] || SSH=ssh
-       if [ "$SSH" = "ssh" ] ; then
-           if $parallel || ! $stdin ; then
+       [ -n "$ONNODE_SSH" ] || ONNODE_SSH=ssh
+       # $ONNODE_SSH must accept the -n option - it can be ignored!
+       if $parallel || ! $stdin ; then
                ssh_opts="-n"
-           fi
-       else
-           : # rsh? All bets are off!
        fi
-    fi
 fi
 
 ######################################################################
 
-nodes=$(get_nodes "$nodespec")
-[ $? != 0 ] && exit 1   # Required to catch exit in above subshell.
+nodes=$(get_nodes "$nodespec") || exit $?
 
 if $quiet ; then
     verbose=false
@@ -346,7 +303,7 @@ else
     # If $nodes contains a space or a newline then assume multiple nodes.
     nl="
 "
-    [ "$nodes" != "${nodes%[ ${nl}]*}" ] && verbose=true
+    [ "$nodes" != "${nodes%[ "${nl}"]*}" ] && verbose=true
 fi
 
 pids=""
@@ -358,25 +315,30 @@ trap 'kill -TERM $pids 2>/dev/null' INT TERM
 # the part of the window where it matter is very small.
 retcode=0
 for n in $nodes ; do
-    set -o pipefail 2>/dev/null
-    if $parallel ; then
-       { exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS "$n" "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; } &
-       pids="${pids} $!"
-    else
-       if $verbose ; then
-           echo >&2 ; echo ">> NODE: $n <<" >&2
+       set -o pipefail 2>/dev/null
+
+       ssh_cmd="$ONNODE_SSH $ssh_opts"
+       if $parallel ; then
+               if $verbose ; then
+                       $ssh_cmd "$n" "$command" 2>&1 | sed -e "s@^@[$n] @"
+               else
+                       $ssh_cmd "$n" "$command"
+               fi &
+               pids="${pids} $!"
+       else
+               if $verbose ; then
+                       echo >&2 ; echo ">> NODE: $n <<" >&2
+               fi
+               {
+                       $ssh_cmd "$n" "$command"
+               } || retcode=$?
        fi
-
-       { exec 3>&1 ; { $SSH $ssh_opts $EXTRA_SSH_OPTS "$n" "$command" | stdout_filter >&3 ; } 2>&1 | stderr_filter ; }
-       [ $? = 0 ] || retcode=$?
-    fi
 done
 
-$parallel && {
-    for p in $pids; do
-       wait "$p"
-       [ $? = 0 ] || retcode=$?
-    done
-}
+if $parallel ; then
+       for p in $pids; do
+               wait "$p" || retcode=$?
+       done
+fi
 
 exit $retcode