Compare commits

...

15 Commits

Author SHA1 Message Date
Matteo Cypriani c661ccd8eb [ssh_tools] tabssh: check dependencies 2019-10-21 18:22:13 +02:00
Matteo Cypriani 81988f3c00 [ssh_tools] tabssh: modernize 2019-10-21 18:19:21 +02:00
Matteo Cypriani 665ca65cd2 [ssh_tools] multiping: don't require fping 2019-10-21 18:06:48 +02:00
Matteo Cypriani a2f5e9a48a [ssh_tools] multissh: don't require pssh 2019-10-21 17:51:59 +02:00
Matteo Cypriani 4f007e1473 [ssh_tools] multissh: modernize 2019-10-21 17:51:59 +02:00
Matteo Cypriani eed73bf99f [ssh_tools] multicopy: don't require multiping 2019-10-21 17:51:59 +02:00
Matteo Cypriani 2b47bb65d2 [ssh_tools] multicopy: don't require pscp
Fallback to plain SCP if parallel-scp is not available.
2019-10-21 17:51:59 +02:00
Matteo Cypriani 410ac3789b [ssh_tools] multiping: check for dependencies
Also some reformatting / modernization of the code.
2019-10-21 17:51:59 +02:00
Matteo Cypriani 8ae30d5e91 [ssh_tools] multicopy: formatting, typos, usage 2019-10-21 16:56:00 +02:00
Matteo Cypriani 0e865d9025 [ssh_tools] multicopy: use getopts, fix nounset bugs 2019-10-21 16:56:00 +02:00
Matteo Cypriani 5e6359cf8d [ssh_tools] multicopy: improve message handling 2019-10-21 16:56:00 +02:00
Matteo Cypriani f3a51827f2 [ssh_tools] multicopy: variables for exit codes
Also enable set -u.
2019-10-21 16:56:00 +02:00
Matteo Cypriani 1a0c6183c4 [ssh_tools] Update README, deprecate
* Updated documentation to point to the new script names.
* The user is now advised to use Ansible if possible. We provide Ansible
  equivalents to these scripts.
2019-10-21 16:14:51 +02:00
Matteo Cypriani a8b48a2771 [ssh_tools] Config is now in ~/.config/ssh_tools
Also removed references to "cluster" in code.
2019-10-21 11:29:29 +02:00
Matteo Cypriani 20b84f300e Renamed cluster/ -> ssh_tools/
And renamed utilities to avoid "cluster".
2019-10-21 11:22:08 +02:00
20 changed files with 566 additions and 398 deletions

View File

@ -1 +0,0 @@
../cluster/cluster-deploy.sh

View File

@ -1 +0,0 @@
../cluster/cluster-ping.sh

View File

@ -1 +0,0 @@
../cluster/cluster-run.sh

View File

@ -1 +0,0 @@
../cluster/cluster-ssh.sh

1
bin/multicopy Symbolic link
View File

@ -0,0 +1 @@
../ssh_tools/multicopy.sh

1
bin/multiping Symbolic link
View File

@ -0,0 +1 @@
../ssh_tools/multiping.sh

1
bin/multissh Symbolic link
View File

@ -0,0 +1 @@
../ssh_tools/multissh.sh

1
bin/tabssh Symbolic link
View File

@ -0,0 +1 @@
../ssh_tools/tabssh.sh

View File

@ -1,81 +0,0 @@
The cluster utilities are script allowing to work in parallel with a
number of remote hosts, using utilities such as Parallel SSH (pssh) or
fping. They all take as first and mandatory positional argument a host
list name “NAME”; the list will be searched according to the following
pattern:
$XDG_CONFIG_HOME/cluster/NAME.lst
(`$XDG_CONFIG_HOME` being equivalent to `$HOME/.config` if unset.)
For example, one can call the `cluster-ping.sh` script typing:
cluster-ping my_hosts
to use the hosts' file `$XDG_CONFIG_HOME/cluster/my_hosts.lst`.
The format of such a .lst file is one line per host name or IP address,
for example:
```
192.168.42.1
192.168.42.3
priam
```
The scripts based on SSH use the local user's login name as remote login;
this can be changed using the `-l` option, that must appear before the
hosts list on the command line, for example:
cluster-run -l root openwrt_machines opkg install screen
The provided scripts are detailed in the sequel.
cluster-ping.sh
---------------
Test the connectivity with the hosts of the list by sending them a ICMP
echo packet.
**Dependency**: `fping`
cluster-ssh.sh
--------------
Open a GNU Screen tab with an interactive SSH session for each host of
the hosts list. Must be run inside of an existing Screen.
**Dependencies**: `screen`, `ssh`
cluster-run.sh
--------------
Run the same command on every host of the hosts list.
**Dependency**: `parallel-ssh` (`pssh`)
cluster-deploy.sh
-----------------
Deploy one or more files in parallel on every host of the hosts list.
The files are copied in the remote user's home directory.
By default, the files are transferred one by one, to make sure you notice
the errors for each file (bad permissions, out of space, etc.), but you
can use the `-P` switch to transfer them all at once (faster).
While it is possible to transfer directories with the default option, to
synchronise directories one would rather use the `-r` option, that uses
prsync rather than pscp to transfer the files. With the `-R` option, the
remote files that are not in the local copy will be deleted (rsync's
`--delete` option). In both cases, the transfer is done with rsync's `-a`
(archive) option.
Please note that unlike rsync, prsync cannot handle multiple local files,
therefore the `-P` option is ignored when passed along with `-r` or `-R`.
**Dependencies**: `parallel-scp` (`pscp`), `parallel-rsync` (`prsync`),
`cluster-ping` (see above)

View File

@ -1 +0,0 @@
cluster-deploy: add option to set a destination directory.

View File

@ -1,153 +0,0 @@
#!/bin/sh
#
# cluster-deploy.sh, Copyright © 2013 Matteo Cypriani <mcy@lm7.fr>
#
# 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.
#
# Deploy files on a number of remote hosts using Parallel SCP.
#set -x
print_usage()
{
echo "Usage:"
echo " $0 [-P] [-r|-R] [-l login] <hosts_list> <file1> [file2 [...]]"
echo
echo "Options:"
echo " -P: transfer files in parallel instead of one by one if possible"
echo " (ignored when -r or -R is used)."
echo " -r: use prsync instead of pscp."
echo " -R: use prsync with option --delete (delete remote files that are"
echo " not in the local copy)."
}
# Parse the optional arguments
while [ $# -gt 2 ] ; do
case $1 in
"-l")
LOGIN="$2"
shift
shift
;;
"-P")
PARALLEL=1
shift
;;
"-r")
RSYNC=1
shift
;;
"-R")
DELETE=1
shift
;;
*)
break
;;
esac
done
# Do we still have at least a host list and a file?
# Note: if the program was wrongly called but still has 2 arguments, for
# example with "cluster-deploy -l root -P my_file", it will try to use
# "-P" as hosts' list and "my_file" as the file to be transfered.
if [ $# -lt 2 ] ; then
print_usage
exit 1
fi
# Check the usage of -r and -R
if [ "$DELETE" = "1" ] ; then
if [ "$RSYNC" = "1" ] ; then
echo "Use either -r or -R, but not both!"
echo
print_usage
exit 2
fi
RSYNC=1
DELETE="-X --delete"
fi
# Ignore -P if rsync is going to be used
if [ "$RSYNC" = "1" ] && [ "$PARALLEL" = "1" ] ; then
echo "Cannot transfer in parallel when using rsync: ignoring -P."
PARALLEL=""
fi
# Check dependencies
PSCP=$(command -v parallel-scp || command -v pscp.pssh || command -v pscp)
PRSYNC=$(command -v parallel-rsync || command -v prsync)
CLUSTERPING=$(command -v cluster-ping)
if [ -z "$RSYNC" ] && [ -z "$PSCP" ] ; then
echo "Parallel SSH (pssh) is required for this script to work."
exit 4
elif [ -z "$PRSYNC" ] ; then
echo "Parallel rsync (prsync) is required for this script to work."
exit 5
elif [ -z "$CLUSTERPING" ] ; then
echo "cluster-ping (which should have been provided along with this"
echo "script) is required for this script to work."
exit 6
fi
# Hosts' list file
HOSTS_LIST_NAME="$1"
if [ -z "$XDG_CONFIG_HOME" ] ; then
XDG_CONFIG_HOME="$HOME/.config"
fi
HOSTS="$XDG_CONFIG_HOME/cluster/${HOSTS_LIST_NAME}.lst"
shift
echo "Using file '$HOSTS' as hosts' list."
if [ ! -f "$HOSTS" ] ; then
echo "The hosts' list file doesn't exist or is not a regular file."
exit 3
fi
# Login
if [ -n "$LOGIN" ] ; then
echo "Login: $LOGIN"
SSH_LOGIN="${LOGIN}@"
LOGIN="-l $LOGIN"
fi
# Test the connection to the first host and get the destination
# directory (home directory of the remote user)
FIRST_HOST=$($CLUSTERPING "$HOSTS_LIST_NAME" 2>/dev/null \
| sed -n "s/ is alive$//p" | head -n1)
if [ -z "$FIRST_HOST" ] ; then
echo "None of the remote hosts is alive."
exit 7
fi
echo "Testing connection to $FIRST_HOST..."
DEST_DIR="$(ssh "${SSH_LOGIN}${FIRST_HOST}" 'echo $HOME' 2>/dev/null)"
if [ -z "$DEST_DIR" ] ; then
echo "Cannot connect to the first alive host. Aborting."
exit 7
fi
echo "Destination directory: $DEST_DIR"
# Transfer the files in parallel...
if [ "$PARALLEL" = "1" ] ; then
# shellcheck disable=SC2086
exec $PSCP -r $LOGIN -h "$HOSTS" -- "$@" "$DEST_DIR"
fi
# ... or one by one
for FILE in "$@" ; do
echo "Deploying '$FILE'..."
if [ ! -e "$FILE" ] ; then
echo "This file doesn't exist, skipping."
continue
fi
if [ "$RSYNC" = "1" ] ; then
# shellcheck disable=SC2086
$PRSYNC -a $DELETE $LOGIN -h "$HOSTS" -- "$FILE" "$DEST_DIR"
else
# shellcheck disable=SC2086
$PSCP -r $LOGIN -h "$HOSTS" -- "$FILE" "$DEST_DIR"
fi
done

View File

@ -1,32 +0,0 @@
#!/bin/sh
#
# cluster-ping.sh, Copyright © 2013 Matteo Cypriani <mcy@lm7.fr>
#
# 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.
#
# Ping a list of remote hosts using fping.
# Check arguments
if [ $# -ne 1 ] ; then
echo "Usage: $0 <hosts_list>"
exit 1
fi
# Hosts' list file
if [ -z "$XDG_CONFIG_HOME" ] ; then
XDG_CONFIG_HOME="$HOME/.config"
fi
HOSTS="$XDG_CONFIG_HOME/cluster/$1.lst"
echo "Using file '$HOSTS' as hosts' list."
if [ ! -f "$HOSTS" ] ; then
echo "The hosts' list file doesn't exist or is not a regular file."
exit 2
fi
# Go!
# shellcheck disable=SC2046
exec fping $(cat "$HOSTS") 2>/dev/null

View File

@ -1,67 +0,0 @@
#!/bin/sh
#
# cluster-run.sh, Copyright © 2013 Matteo Cypriani <mcy@lm7.fr>
#
# 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.
#set -x
print_usage()
{
echo "Usage: $0 [-l login] <hosts_list> <command>"
}
# Do we have at least a host list and a command?
if [ $# -lt 2 ] ; then
print_usage >&2
exit 1
fi
# Parse the optional arguments
if [ "$1" = "-l" ] ; then
LOGIN="$2"
shift
shift
# Do we still have at least a host list and a command?
if [ $# -lt 2 ] ; then
print_usage
exit 3
fi
fi
# Check dependencies
PSSH=$(command -v parallel-ssh || command -v pssh)
if [ -z "$PSSH" ] ; then
echo "Parallel SSH (pssh) is required for this script to work."
exit 4
fi
# Hosts' list file
if [ -z "$XDG_CONFIG_HOME" ] ; then
XDG_CONFIG_HOME="$HOME/.config"
fi
HOSTS="$XDG_CONFIG_HOME/cluster/$1.lst"
shift
echo "Using file '$HOSTS' as hosts' list."
if [ ! -f "$HOSTS" ] ; then
echo "The hosts' list file doesn't exist or is not a regular file."
exit 2
fi
# Login
if [ -n "$LOGIN" ] ; then
echo "Login: $LOGIN"
LOGIN="-l $LOGIN"
fi
echo "Command:" "$@"
# shellcheck disable=SC2086
exec $PSSH --print $LOGIN -h "$HOSTS" -- "$@"

View File

@ -1,60 +0,0 @@
#!/bin/sh
#
# cluster-ssh.sh, Copyright © 2013 Matteo Cypriani <mcy@lm7.fr>
#
# 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.
#
# Open an SSH interactive shell on a list of remote hosts, opening one
# GNU Screen tab per host.
print_usage()
{
echo "Usage: $0 [-l login] <hosts_list>"
}
# We must have either 3 arguments...
if [ $# -eq 3 ] ; then
# Parse the optional arguments
if [ "$1" = "-l" ] ; then
LOGIN="$2"
shift
shift
else # Option unknown
print_usage
exit 1
fi
# ... or only 1
elif [ $# -ne 1 ] ; then
print_usage
exit 3
fi
# Hosts' list file
if [ -z "$XDG_CONFIG_HOME" ] ; then
XDG_CONFIG_HOME="$HOME/.config"
fi
HOSTS_FILE="$XDG_CONFIG_HOME/cluster/$1.lst"
shift
echo "Using file '$HOSTS_FILE' as hosts' list."
if [ ! -f "$HOSTS_FILE" ] ; then
echo "The hosts' list file doesn't exist or is not a regular file."
exit 2
fi
# Login
if [ -n "$LOGIN" ] ; then
echo "Login: $LOGIN"
LOGIN="${LOGIN}@"
fi
# Create the screen tabs
while read -r HOST ; do
SSH="ssh ${LOGIN}${HOST}"
# shellcheck disable=SC2086
screen -t "$SSH" $SSH
done <"$HOSTS_FILE"

105
ssh_tools/README.md Normal file
View File

@ -0,0 +1,105 @@
Use Ansible instead
===================
These utilities are script allowing one to work in parallel with a number of
remote hosts, using utilities such as Parallel SSH (pssh) or fping. Nowadays,
you're much better off using Ansible, which covers everything these scripts do,
and much more. The only exception might be `tabssh.sh`.
Original documentation
======================
All these scripts take as first and mandatory positional argument a host list
name “NAME”; the list will be searched according to the following pattern:
$XDG_CONFIG_HOME/ssh_tools/NAME.lst
(`$XDG_CONFIG_HOME` being equivalent to `$HOME/.config` if unset.)
For example, one can call the `multiping.sh` script typing:
multiping my_hosts
to use the hosts' file `$XDG_CONFIG_HOME/ssh_tools/my_hosts.lst`.
The format of such a .lst file is one line per host name or IP address,
for example:
```
192.168.42.1
192.168.42.3
priam
```
The scripts based on SSH use the local user's login name as remote login;
this can be changed using the `-l` option, that must appear before the
hosts list on the command line, for example:
multissh -l root openwrt_machines opkg install screen
The provided scripts are detailed in the sequel.
multiping.sh
------------
Tests the connectivity with the hosts of the list by sending them a ICMP
echo packet.
**Dependency**: `fping`
**Ansible replacement**:
ansible <group> -m ping
tabssh.sh
---------
Opens a GNU Screen tab with an interactive SSH session for each host of
the hosts list. Must be run inside of an existing Screen.
**Dependencies**: `screen`, `ssh`
**Ansible replacement**: not really. Maybe see this StackOverflow question for
inspiration:
<https://stackoverflow.com/questions/47887379/how-could-i-open-a-ssh-shell-to-remote-with-ansible>
multissh.sh
-----------
Runs the same command on every host of the hosts list.
**Dependency**: `parallel-ssh` (`pssh`)
**Ansible replacement**: use Ansible's `command` module (i.e. the default
module), or the `shell` module if using pipes or redirections.
ansible <group> -a '<command>'
ansible <group> -m shell -a '<command with pipes>'
multicopy.sh
------------
Deploys one or more files in parallel on every host of the hosts list.
The files are copied in the remote user's home directory.
By default, the files are transferred one by one, to make sure you notice
the errors for each file (bad permissions, out of space, etc.), but you
can use the `-P` switch to transfer them all at once (which is much faster).
While it is possible to transfer directories with the default option, to
synchronise directories one would rather use the `-r` option, that uses
prsync rather than pscp to transfer the files. With the `-R` option, the
remote files that are not in the local copy will be deleted (rsync's
`--delete` option). In both cases, the transfer is done with rsync's `-a`
(archive) option.
Please note that unlike rsync, prsync cannot handle multiple local files,
therefore the `-P` option is ignored when passed along with `-r` or `-R`.
**Dependencies (optional)**: `parallel-scp` (`pscp`), `parallel-rsync`
(`prsync`), `multiping` (see above)
**Ansible replacement**: use Ansible `copy` module. See also modules `fetch`
(to retrieve files instead of pushing them), `synchronize`, `rsync` and
`unarchive`.
ansible <group> -m copy -a 'src=/local/path dest=/remote/path'

1
ssh_tools/TODO Normal file
View File

@ -0,0 +1 @@
multicopy: add option to set a destination directory.

203
ssh_tools/multicopy.sh Executable file
View File

@ -0,0 +1,203 @@
#!/bin/sh
#
# multicopy.sh, Copyright © 2013, 2019 Matteo Cypriani <mcy@lm7.fr>
# (Formerly named cluster-deploy.sh)
#
# 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.
#
# Deploy files on a number of remote hosts using Parallel SCP.
#set -x
set -u
# Exit codes
readonly EXIT_SUCCESS=0
readonly EXIT_USAGE=127
readonly EXIT_DEPENDENCY=4
readonly EXIT_HOSTS_LIST=6
readonly EXIT_HOSTS_DEAD=7
readonly EXIT_CONNECTION=8
print_usage()
{
cat <<EOF
Usage:
$0 -h
$0 [-P] [-r|-R] [-l <login>] <hosts_list> <file1> [file2 [...]]
Options:
-h Print this help message.
-l <login>
Login remotely as <login>.
-P Transfer files in parallel instead of one by one whenever possible
(ignored when -r or -R is used).
-r Use prsync instead of pscp.
-R Use prsync's --delete option (delete remote files that are not in
the local copy).
<hosts_list> is the list of remote hosts on which the file(s) will be copied.
EOF
}
bad_usage()
{
err "$@"
echo >&2
print_usage >&2
exit $EXIT_USAGE
}
err()
{
printf 'Error! ' >&2
printf '%s\n' "$@" >&2
}
warn()
{
printf 'Warning! ' >&2
printf '%s\n' "$@" >&2
}
# Copy file $FILE to the remote hosts using plain old SCP
scp_copy()
{
grep -v '^#' "$HOSTS" | while read -r host ; do
[ -z "$host" ] && continue
echo "Deploying '$FILE' to '$host'..."
scp -r "$FILE" "${SSH_LOGIN}${host}:${DEST_DIR}"
done
}
# Parse CLI options
LOGIN=
PARALLEL=
RSYNC=
DELETE=
while getopts hl:PrR option ; do
case $option in
h) print_usage
exit $EXIT_SUCCESS
;;
l) LOGIN="$OPTARG" ;;
P) PARALLEL=1 ;;
r) RSYNC=1 ;;
R) DELETE=1 ;;
\?) bad_usage "Bad option."
esac
done
shift $((OPTIND - 1))
# Do we still have at least a host list and a file?
[ $# -lt 2 ] && bad_usage "Wrong number of arguments."
# Check the usage of -r and -R
if [ "$DELETE" = 1 ] ; then
[ "$RSYNC" = 1 ] && bad_usage "Use either -r or -R, but not both."
RSYNC=1
DELETE="-X --delete"
fi
# Ignore -P if rsync is going to be used
if [ "$RSYNC" = 1 ] && [ "$PARALLEL" = 1 ] ; then
warn "Cannot transfer in parallel when using rsync: ignoring -P."
PARALLEL=
fi
# Check dependencies
if [ "$RSYNC" = 1 ] ; then
PRSYNC=$(command -v parallel-rsync || command -v prsync)
if [ -z "$PRSYNC" ] ; then
err "Parallel rsync (prsync) is required for this script to work with -r or -R."
exit $EXIT_DEPENDENCY
fi
else # $RSYNC != 1
PSCP=$(command -v parallel-scp || command -v pscp.pssh || command -v pscp)
if [ -z "$PSCP" ] ; then
warn "Parallel SSH (pssh) is not installed. Install it for best results."
if [ "$PARALLEL" = 1 ] ; then
warn "Parallel copy will not work without Parallel SSH. Ignoring -P."
PARALLEL=
fi
fi
fi
MULTIPING=$(command -v multiping)
if [ -z "$MULTIPING" ] ; then
warn "multiping (which should have been provided along with this" \
"script) is not available. For best results, make sure it is" \
"reachable from your PATH."
fi
# Hosts list file
HOSTS_LIST_NAME="$1"
shift
[ -z ${XDG_CONFIG_HOME+x} ] && XDG_CONFIG_HOME="$HOME/.config"
HOSTS="$XDG_CONFIG_HOME/ssh_tools/${HOSTS_LIST_NAME}.lst"
echo "Using file '$HOSTS' as hosts list."
if [ ! -f "$HOSTS" ] ; then
err "The hosts list file doesn't exist or is not a regular file."
exit $EXIT_HOSTS_LIST
fi
# Login
SSH_LOGIN=
if [ -n "$LOGIN" ] ; then
echo "Login: $LOGIN"
SSH_LOGIN="${LOGIN}@"
LOGIN="-l $LOGIN"
fi
# Test the connection to the first alive host
if [ -n "$MULTIPING" ] ; then
FIRST_HOST=$($MULTIPING "$HOSTS_LIST_NAME" 2>/dev/null \
| sed -n "s/ is alive$//p" | head -n1)
if [ -z "$FIRST_HOST" ] ; then
err "None of the remote hosts is alive."
exit $EXIT_HOSTS_DEAD
fi
else # multiping is not available
warn "multiping is not available, using the first host in the hosts list."
FIRST_HOST="$(grep -v '^#' "$HOSTS" | head -n 1)"
fi
# Get the destination directory (home directory of the remote user)
echo "Testing connection to $FIRST_HOST..."
DEST_DIR="$(ssh "${SSH_LOGIN}${FIRST_HOST}" 'echo $HOME' 2>/dev/null)"
if [ -z "$DEST_DIR" ] ; then
err "Cannot connect to the first alive host. Aborting."
exit $EXIT_CONNECTION
fi
echo "Destination directory: $DEST_DIR"
# Transfer the files in parallel...
if [ "$PARALLEL" = 1 ] ; then
# shellcheck disable=SC2086
exec $PSCP -r $LOGIN -h "$HOSTS" -- "$@" "$DEST_DIR"
fi
# ... or one by one
for FILE in "$@" ; do
echo "Deploying '$FILE'..."
if [ ! -e "$FILE" ] ; then
warn "This file doesn't exist, skipping."
continue
fi
if [ "$RSYNC" = 1 ] ; then
# shellcheck disable=SC2086
$PRSYNC -a $DELETE $LOGIN -h "$HOSTS" -- "$FILE" "$DEST_DIR"
continue
fi
if [ -n "$PSCP" ] ; then
# shellcheck disable=SC2086
$PSCP -r $LOGIN -h "$HOSTS" -- "$FILE" "$DEST_DIR"
continue
fi
# If we're still here, that means we'll have to copy with plain SCP
scp_copy
done

64
ssh_tools/multiping.sh Executable file
View File

@ -0,0 +1,64 @@
#!/bin/sh
#
# multiping.sh, Copyright © 2013, 2019 Matteo Cypriani <mcy@lm7.fr>
# (Formerly named cluster-ping.sh)
#
# 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.
#
# Ping a list of remote hosts using fping.
#set -x
set -u
readonly EXIT_USAGE=127
readonly EXIT_HOSTS_LIST=6
err()
{
printf 'Error! ' >&2
printf '%s\n' "$@" >&2
}
warn()
{
printf 'Warning! ' >&2
printf '%s\n' "$@" >&2
}
ping_hosts()
{
grep -v '^#' "$HOSTS" | while read -r host ; do
[ -z "$host" ] && continue
ping -c 1 -W 1 "$host" >/dev/null 2>&1 && echo "$host is alive"
done
}
# Check arguments
if [ $# -ne 1 ] ; then
echo "Usage: $0 <hosts_list>" >&2
exit $EXIT_USAGE
fi
FPING=$(command -v fping)
[ -z "$FPING" ] && warn "fping is not available. Install it for best results."
# Hosts list file
[ -z ${XDG_CONFIG_HOME+x} ] && XDG_CONFIG_HOME="$HOME/.config"
HOSTS="$XDG_CONFIG_HOME/ssh_tools/$1.lst"
echo "Using file '$HOSTS' as hosts list."
if [ ! -f "$HOSTS" ] ; then
err "The hosts list file doesn't exist or is not a regular file."
exit $EXIT_HOSTS_LIST
fi
if [ -n "$FPING" ] ; then
# shellcheck disable=SC2046
exec "$FPING" $(cat "$HOSTS") 2>/dev/null
fi
# Fall back to good old ping if fping is not available
ping_hosts

102
ssh_tools/multissh.sh Executable file
View File

@ -0,0 +1,102 @@
#!/bin/sh
#
# multissh.sh, Copyright © 2013, 2019 Matteo Cypriani <mcy@lm7.fr>
# (Formerly named cluster-run.sh)
#
# 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.
#set -x
set -u
# Exit codes
readonly EXIT_SUCCESS=0
readonly EXIT_USAGE=127
readonly EXIT_HOSTS_LIST=6
print_usage()
{
echo "Usage: $0 [-l login] <hosts_list> <command>"
}
bad_usage()
{
err "$@"
echo >&2
print_usage >&2
exit $EXIT_USAGE
}
err()
{
printf 'Error! ' >&2
printf '%s\n' "$@" >&2
}
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
}
# Do we have at least a host list and a command?
[ $# -lt 2 ] && bad_usage "Wrong number of arguments."
# Parse the optional arguments
LOGIN=
if [ "$1" = "-l" ] ; then
LOGIN="$2"
shift
shift
# Do we still have at least a host list and a command?
[ $# -lt 2 ] && bad_usage "Wrong number of arguments."
fi
# Check dependencies
PSSH=$(command -v parallel-ssh || command -v pssh)
if [ -z "$PSSH" ] ; then
warn "Parallel SSH (pssh) is not available. Install it for best results."
fi
# Hosts list file
[ -z ${XDG_CONFIG_HOME+x} ] && XDG_CONFIG_HOME="$HOME/.config"
HOSTS_LIST_NAME="$1"
shift
HOSTS="$XDG_CONFIG_HOME/ssh_tools/${HOSTS_LIST_NAME}.lst"
echo "Using file '$HOSTS' as hosts list."
if [ ! -f "$HOSTS" ] ; then
err "The hosts list file doesn't exist or is not a regular file."
exit $EXIT_HOSTS_LIST
fi
# Login
if [ -n "$LOGIN" ] ; then
echo "Login: $LOGIN"
LOGIN="-l $LOGIN"
fi
echo "Command:" "$@"
if [ -n "$PSSH" ] ; then
# shellcheck disable=SC2086
exec $PSSH --print $LOGIN -h "$HOSTS" -- "$@"
else
ssh_command "$@"
fi

87
ssh_tools/tabssh.sh Executable file
View File

@ -0,0 +1,87 @@
#!/bin/sh
#
# tabssh.sh, Copyright © 2013 Matteo Cypriani <mcy@lm7.fr>
# (Formerly named cluster-ssh.sh)
#
# 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.
#
# Open an SSH interactive shell on a list of remote hosts, opening one
# GNU Screen tab per host.
#set -x
set -u
# Exit codes
readonly EXIT_SUCCESS=0
readonly EXIT_USAGE=127
readonly EXIT_DEPENDENCY=4
readonly EXIT_HOSTS_LIST=6
print_usage()
{
echo "Usage: $0 [-l login] <hosts_list>"
}
bad_usage()
{
err "$@"
echo >&2
print_usage >&2
exit $EXIT_USAGE
}
err()
{
printf 'Error! ' >&2
printf '%s\n' "$@" >&2
}
LOGIN=
# We must have either 3 arguments...
if [ $# -eq 3 ] ; then
# Only -l is a valid option
[ "$1" = "-l" ] || bad_usage "Option '$1' unknown."
LOGIN="$2"
shift
shift
# ... or only 1 argument
elif [ $# -ne 1 ] ; then
bad_usage "Wrong number of arguments."
fi
# Check dependencies
SCREEN=$(command -v screen)
if [ -z "$SCREEN" ] ; then
err "GNU screen is required by this script."
exit $EXIT_DEPENDENCY
fi
# Hosts list file
[ -z ${XDG_CONFIG_HOME+x} ] && XDG_CONFIG_HOME="$HOME/.config"
HOSTS_LIST_NAME="$1"
shift
HOSTS="$XDG_CONFIG_HOME/ssh_tools/${HOSTS_LIST_NAME}.lst"
echo "Using file '$HOSTS' as hosts list."
if [ ! -f "$HOSTS" ] ; then
err "The hosts list file doesn't exist or is not a regular file."
exit $EXIT_HOSTS_LIST
fi
# Login
if [ -n "$LOGIN" ] ; then
echo "Login: $LOGIN"
LOGIN="${LOGIN}@"
fi
# Create the screen tabs
while read -r HOST ; do
SSH="ssh ${LOGIN}${HOST}"
# shellcheck disable=SC2086
$SCREEN -t "$SSH" $SSH
done <"$HOSTS"