150 lines
3.9 KiB
Bash
Executable File
150 lines
3.9 KiB
Bash
Executable File
#!/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" -a "$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 [ "$RSYNC" = "" -a "$PSCP" = "" ] ; then
|
|
echo "Parallel SSH (pssh) is required for this script to work."
|
|
exit 4
|
|
elif [ "$PRSYNC" = "" ] ; then
|
|
echo "Parallel rsync (prsync) is required for this script to work."
|
|
exit 5
|
|
elif [ "$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 [ "$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 [ "$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 [ "$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 [ "$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
|
|
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
|
|
$PRSYNC -a $DELETE $LOGIN -h "$HOSTS" -- "$FILE" "$DEST_DIR"
|
|
else
|
|
$PSCP -r $LOGIN -h "$HOSTS" -- "$FILE" "$DEST_DIR"
|
|
fi
|
|
done
|