2013-04-29 22:43:41 +02:00
|
|
|
#!/bin/sh
|
|
|
|
#
|
2019-10-21 17:13:32 +02:00
|
|
|
# multissh.sh, Copyright © 2013, 2019 Matteo Cypriani <mcy@lm7.fr>
|
2019-10-21 11:29:29 +02:00
|
|
|
# (Formerly named cluster-run.sh)
|
2013-04-29 22:43:41 +02:00
|
|
|
#
|
|
|
|
# This program is free software. It comes without any warranty, to
|
|
|
|
# the extent permitted by applicable law. You can redistribute it
|
|
|
|
# and/or modify it under the terms of the Do What The Fuck You Want
|
|
|
|
# To Public License, Version 2, as published by Sam Hocevar. See
|
|
|
|
# http://sam.zoy.org/wtfpl/COPYING for more details.
|
|
|
|
#
|
|
|
|
# Run a command on a list of remote hosts using Parallel SSH.
|
|
|
|
|
2013-05-01 22:12:09 +02:00
|
|
|
#set -x
|
2019-10-21 17:13:32 +02:00
|
|
|
set -u
|
|
|
|
|
|
|
|
# Exit codes
|
|
|
|
readonly EXIT_SUCCESS=0
|
|
|
|
readonly EXIT_USAGE=127
|
|
|
|
readonly EXIT_HOSTS_LIST=6
|
2013-05-01 22:12:09 +02:00
|
|
|
|
|
|
|
print_usage()
|
|
|
|
{
|
|
|
|
echo "Usage: $0 [-l login] <hosts_list> <command>"
|
|
|
|
}
|
|
|
|
|
2019-10-21 17:13:32 +02:00
|
|
|
bad_usage()
|
|
|
|
{
|
|
|
|
err "$@"
|
|
|
|
echo >&2
|
2018-04-11 22:56:01 +02:00
|
|
|
print_usage >&2
|
2019-10-21 17:13:32 +02:00
|
|
|
exit $EXIT_USAGE
|
|
|
|
}
|
|
|
|
|
|
|
|
err()
|
|
|
|
{
|
|
|
|
printf 'Error! ' >&2
|
|
|
|
printf '%s\n' "$@" >&2
|
|
|
|
}
|
|
|
|
|
2019-10-21 17:51:31 +02:00
|
|
|
warn()
|
|
|
|
{
|
|
|
|
printf 'Warning! ' >&2
|
|
|
|
printf '%s\n' "$@" >&2
|
|
|
|
}
|
|
|
|
|
|
|
|
ssh_command()
|
|
|
|
{
|
|
|
|
grep -v '^#' "$HOSTS" | while read -r host ; do
|
|
|
|
[ -z "$host" ] && continue
|
|
|
|
echo "Executing command on '$host'..."
|
|
|
|
# shellcheck disable=SC2086
|
|
|
|
ssh ${LOGIN} "${host}" -- "$@" </dev/null
|
|
|
|
# Note: </dev/null is to prevent ssh from swallowing stdin (see SC2095).
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2019-10-21 17:13:32 +02:00
|
|
|
# Do we have at least a host list and a command?
|
|
|
|
[ $# -lt 2 ] && bad_usage "Wrong number of arguments."
|
2013-04-29 22:43:41 +02:00
|
|
|
|
2013-05-02 16:56:28 +02:00
|
|
|
# Parse the optional arguments
|
2019-10-21 17:13:32 +02:00
|
|
|
LOGIN=
|
2013-05-02 16:56:28 +02:00
|
|
|
if [ "$1" = "-l" ] ; then
|
|
|
|
LOGIN="$2"
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
|
|
|
|
# Do we still have at least a host list and a command?
|
2019-10-21 17:13:32 +02:00
|
|
|
[ $# -lt 2 ] && bad_usage "Wrong number of arguments."
|
2013-05-01 22:12:09 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
# Check dependencies
|
2013-04-29 22:43:41 +02:00
|
|
|
PSSH=$(command -v parallel-ssh || command -v pssh)
|
2018-04-11 22:56:01 +02:00
|
|
|
if [ -z "$PSSH" ] ; then
|
2019-10-21 17:51:31 +02:00
|
|
|
warn "Parallel SSH (pssh) is not available. Install it for best results."
|
2013-04-29 22:43:41 +02:00
|
|
|
fi
|
|
|
|
|
2019-10-21 17:13:32 +02:00
|
|
|
# Hosts list file
|
|
|
|
[ -z ${XDG_CONFIG_HOME+x} ] && XDG_CONFIG_HOME="$HOME/.config"
|
|
|
|
HOSTS_LIST_NAME="$1"
|
2013-04-29 22:43:41 +02:00
|
|
|
shift
|
2019-10-21 17:13:32 +02:00
|
|
|
HOSTS="$XDG_CONFIG_HOME/ssh_tools/${HOSTS_LIST_NAME}.lst"
|
|
|
|
echo "Using file '$HOSTS' as hosts list."
|
2013-05-20 20:46:39 +02:00
|
|
|
if [ ! -f "$HOSTS" ] ; then
|
2019-10-21 17:13:32 +02:00
|
|
|
err "The hosts list file doesn't exist or is not a regular file."
|
|
|
|
exit $EXIT_HOSTS_LIST
|
2013-05-20 20:46:39 +02:00
|
|
|
fi
|
2013-04-29 22:43:41 +02:00
|
|
|
|
2013-05-01 22:12:09 +02:00
|
|
|
# Login
|
2018-04-11 22:56:01 +02:00
|
|
|
if [ -n "$LOGIN" ] ; then
|
2013-05-01 22:12:09 +02:00
|
|
|
echo "Login: $LOGIN"
|
|
|
|
LOGIN="-l $LOGIN"
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Command:" "$@"
|
|
|
|
|
2019-10-21 17:51:31 +02:00
|
|
|
if [ -n "$PSSH" ] ; then
|
|
|
|
# shellcheck disable=SC2086
|
|
|
|
exec $PSSH --print $LOGIN -h "$HOSTS" -- "$@"
|
|
|
|
else
|
|
|
|
ssh_command "$@"
|
|
|
|
fi
|