removed old code. moved to version 0.3
This commit is contained in:
parent
d57b2e3ee3
commit
5e796c23aa
51
README.md
51
README.md
|
@ -1,37 +1,28 @@
|
|||
sshbackup
|
||||
=========
|
||||
|
||||
bash script which does incremental backups through ssh using rsync.
|
||||
it is supposed to be amazingly easy to install, configure and maintain.
|
||||
for automated backups configure a sshkey for the user running sshbackup.
|
||||
|
||||
you must add following to /etc/sudoers on your remote servers as well to
|
||||
make automated backups work
|
||||
```backupuser ALL=(root)NOPASSWD: /usr/bin/rsync```
|
||||
|
||||
installation/usage:
|
||||
* put the file sshbackup.sh somewhere you like to have it and run it as root.
|
||||
* root must have a sshkey to connect to remote machines.
|
||||
* first option must be the sourcefile.
|
||||
* sourcefile example can be found in sourcefile sample.
|
||||
* logs go to /var/log/sshbackup.log
|
||||
* configure a cron job for continuous backups
|
||||
|
||||
in order to have mail notifications working you need your cron system be able
|
||||
to send mails with the MAILTO directive in crontab.
|
||||
the sshbackup scripts only output to stdout will be when an error occures.
|
||||
cron will send you a mail on output to stdout of a script which is run by it.
|
||||
|
||||
|
||||
|
||||
bugs/features:
|
||||
* the remote sourcepath must be able to be listed by the remote backup user
|
||||
|
||||
|
||||
todo/wanted: (roadmap)
|
||||
* deploy feature (deploy required settings to remote machine)
|
||||
* better notification system (for now its just crons mail on output feature)
|
||||
* check if destination is full
|
||||
|
||||
|
||||
license:
|
||||
* public domain (do whatever, i'm not claiming anything)
|
||||
|
||||
a example config for default values in ~/.sshbackup looks like this:
|
||||
```
|
||||
#rsync options.
|
||||
rsyncoptions="-pogEthrzl --numeric-ids --no-motd"
|
||||
#dotglob option removes bug while rsyncing folder with no visible files in it.
|
||||
remotecmd="shopt -s dotglob; /usr/bin/sudo /usr/bin/rsync"
|
||||
localcmd="/usr/bin/rsync"
|
||||
sshkeyfile="$HOME/.ssh/id_rsa"
|
||||
```
|
||||
|
||||
if you are running sshbackup through cron configure the MAILTO
|
||||
directive for getting error notifications.
|
||||
|
||||
a list file could look like this
|
||||
```
|
||||
david@dev.socialnerds.org:/home/david /home/david/Downloads/devhome 30
|
||||
backupuser@dev.socialnerds.org:/home/gollum/ /home/david/Downloads/gollum
|
||||
/home/david/something /home/david/backup 5
|
||||
```
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# in here are the backup sources supposed to be
|
||||
# one source per line (no tailing slashes)
|
||||
|
||||
# <user@remotemachine:/remote/path> </local/path> <versions>
|
||||
|
||||
user@server1.example.com:/srv/projects/* /home/david/testback/git 3
|
||||
user@server2.example.com:/srv/backup/* /home/david/testback/duffman 3
|
||||
user2@server3:/media/storage2/* /home/david/testback/cartman 30
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
#!/bin/sh
|
||||
|
||||
# ************************************* #
|
||||
# #
|
||||
# sshbackup #
|
||||
# #
|
||||
# ************************************* #
|
||||
|
||||
# **** config section ****
|
||||
version="0.3"
|
||||
author="david@socialnerds.org"
|
||||
|
||||
configfile="$HOME/.sshbackup"
|
||||
#rsync options.
|
||||
rsyncoptions="-pogEthrzl --numeric-ids --no-motd"
|
||||
#dotglob option removes bug while rsyncing folder with no visible files in it.
|
||||
remotecmd="shopt -s dotglob; /usr/bin/sudo /usr/bin/rsync"
|
||||
localcmd="/usr/bin/rsync"
|
||||
|
||||
sshkeyfile="$HOME/.ssh/id_rsa"
|
||||
|
||||
versions=999
|
||||
config=0
|
||||
sshkey=0
|
||||
list=0
|
||||
options=$*
|
||||
|
||||
|
||||
# **** function definitions ****
|
||||
bashtrap()
|
||||
{
|
||||
|
||||
echo
|
||||
echo "CTRL+C detected."
|
||||
echo "commiting suicide."
|
||||
exit 1
|
||||
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
|
||||
echo
|
||||
echo "usage: sshbackup <options> source destination [versions]"
|
||||
echo "source/destination example: [[user@]server:]/path/to/files"
|
||||
echo
|
||||
echo "OPTIONS:"
|
||||
echo " -h, --help show this message"
|
||||
echo " -v, --version version information"
|
||||
echo
|
||||
echo " -c, --config <file> alternate config file [~/.sshbackup]"
|
||||
echo " -l, --list <file> list of sources and destinations"
|
||||
echo " -s, --sshkey <file> alternate sshkey [~/.ssh/id_rsa]"
|
||||
echo
|
||||
|
||||
}
|
||||
|
||||
version()
|
||||
{
|
||||
|
||||
echo
|
||||
echo -e "vesion: \033[1;37m$version\033[0m"
|
||||
echo "author: $author"
|
||||
echo
|
||||
|
||||
}
|
||||
|
||||
preflight()
|
||||
{
|
||||
|
||||
#amiroot?
|
||||
if [ $(whoami) != "root" ]; then
|
||||
echo "aborting mission. you must be root."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#source and destination path?
|
||||
if [ -z $sourcepath ]; then
|
||||
echo "aborting mission. no source path given."
|
||||
return 1
|
||||
elif [ -z $destinationpath ]; then
|
||||
echo "aborting mission. no destination path given."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#if remote source or destination check for sshkey
|
||||
if [[ $sourcepath =~ .*@.* ]] || [[ $destinationpath =~ .*@.* ]]; then
|
||||
if [ -r $sshkeyfile ]; then
|
||||
#echo "sshkeyfile found. continuing."
|
||||
:
|
||||
else
|
||||
echo "aborting mission. no sshkey found."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
}
|
||||
|
||||
sshbackup()
|
||||
{
|
||||
|
||||
#creating local rsync options var
|
||||
local cmdopt="$rsyncoptions"
|
||||
|
||||
#move existing versions
|
||||
local num=$versions
|
||||
while [ -d "$destinationpath/0" ]; do
|
||||
if [ -d "$destinationpath/$num" ]; then
|
||||
mv $destinationpath/$num $destinationpath/$((num+1))
|
||||
fi
|
||||
let num--
|
||||
done
|
||||
|
||||
#create destinationpath if not existing
|
||||
mkdir -p $destinationpath/0
|
||||
|
||||
#add link-destination option if existing
|
||||
if [ -d $destinationpath/1 ]; then
|
||||
cmdopt="$cmdopt --link-dest=$destinationpath/1"
|
||||
fi
|
||||
|
||||
#run rsync
|
||||
$localcmd $cmdopt -e "ssh -q -i $sshkeyfile" --rsync-path="$remotecmd" $sourcepath $destinationpath/0
|
||||
if [ $? -ne "0" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
#removing obsolet version(s)
|
||||
local i=1
|
||||
while [ -d $destinationpath/$((versions+i)) ]; do
|
||||
rm -rf $destinationpath/$((versions+i))
|
||||
let i++
|
||||
done
|
||||
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
|
||||
# **** start of script ****
|
||||
|
||||
#initialize bashtrap
|
||||
trap bashtrap INT
|
||||
|
||||
# **** option handler ****
|
||||
if [ -z $1 ]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
for option in $options; do
|
||||
case "$option" in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-v|--version)
|
||||
version
|
||||
exit 0
|
||||
;;
|
||||
-c|--config)
|
||||
config=1
|
||||
;;
|
||||
-l|--list)
|
||||
list=1
|
||||
;;
|
||||
-s|--sshkey)
|
||||
sshkey=1
|
||||
;;
|
||||
*)
|
||||
if [ $config -eq 1 ]; then
|
||||
if [ -r "$option" ]; then
|
||||
configfile=$option
|
||||
config=0
|
||||
else
|
||||
echo "aborting mission. cannot read configfile. [$option]"
|
||||
exit 1
|
||||
fi
|
||||
elif [ $sshkey -eq 1 ]; then
|
||||
if [ -r $option ]; then
|
||||
sshkeyfile=$option
|
||||
sshkey=0
|
||||
else
|
||||
echo "aborting mission. cannot read sshkeyfile. [$option]"
|
||||
exit 1
|
||||
fi
|
||||
elif [ $list -eq 1 ]; then
|
||||
if [ -r $option ]; then
|
||||
listfile=$option
|
||||
list=0
|
||||
else
|
||||
echo "aborting mission. cannot read listfile. [$option]"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [[ $option =~ ^-.* ]]; then
|
||||
echo "aborting mission. unknown option given. [$option]"
|
||||
usage
|
||||
exit 1
|
||||
#TODO: what if source or destination is a number?
|
||||
elif [ -z "${option//[0-9]/}" ]; then
|
||||
versions="$option"
|
||||
else
|
||||
if [ -z "$sourcepath" ]; then
|
||||
if [[ $option =~ .*@.* ]]; then
|
||||
sourcepath="${option%/}/"
|
||||
elif [[ $option =~ ^/.* ]]; then
|
||||
sourcepath="${option%/}/"
|
||||
else
|
||||
sourcepath="$(pwd)/${option%/}/"
|
||||
fi
|
||||
else
|
||||
if [ -z "$destinationpath" ]; then
|
||||
if [[ $option =~ ^/.* ]]; then
|
||||
destinationpath="${option%/}"
|
||||
else
|
||||
destinationpath="$(pwd)/${option%/}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -r "$configfile" ]; then
|
||||
source "$configfile"
|
||||
fi
|
||||
|
||||
#read list if listfile is given
|
||||
if [ -r "$listfile" ]; then
|
||||
while read line; do
|
||||
# find first letter
|
||||
fletter=${line:0:1}
|
||||
if [ -z $fletter ]; then
|
||||
#skip line it's empty
|
||||
:
|
||||
elif [ $fletter = "#" ]; then
|
||||
#skip line it's a comment
|
||||
:
|
||||
else
|
||||
sourcepath=""
|
||||
destinationpath=""
|
||||
for option in $line; do
|
||||
if [ -z "${option//[0-9]/}" ]; then
|
||||
versions="$option"
|
||||
else
|
||||
if [ -z "$sourcepath" ]; then
|
||||
if [[ $option =~ .*@.* ]]; then
|
||||
sourcepath="${option%/}/"
|
||||
elif [[ $option =~ ^/.* ]]; then
|
||||
sourcepath="${option%/}/"
|
||||
else
|
||||
sourcepath="$(pwd)/${option%/}/"
|
||||
fi
|
||||
else
|
||||
if [ -z "$destinationpath" ]; then
|
||||
if [[ $option =~ ^/.* ]]; then
|
||||
destinationpath="${option%/}"
|
||||
else
|
||||
destinationpath="$(pwd)/${option%/}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if ( preflight ); then
|
||||
sshbackup
|
||||
fi
|
||||
fi
|
||||
done < "$listfile"
|
||||
else
|
||||
if ( preflight ); then
|
||||
sshbackup
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# **** end of script ****
|
||||
exit 0
|
226
sshbackup.sh
226
sshbackup.sh
|
@ -1,226 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
|
||||
# ************************************* #
|
||||
# #
|
||||
# sshbackup #
|
||||
# #
|
||||
# ************************************* #
|
||||
|
||||
|
||||
# **** config section ****
|
||||
# do not touch as long as you're not me
|
||||
author="david@socialnerds.org"
|
||||
version="0.2.0"
|
||||
|
||||
#rsync options.
|
||||
options="-pogEthrzl --numeric-ids --no-motd"
|
||||
#dotglob option removes bug while rsyncing folder with no visible files in it.
|
||||
remotecmd="shopt -s dotglob; /usr/bin/sudo /usr/bin/rsync"
|
||||
localcmd="/usr/bin/rsync"
|
||||
|
||||
#where should i write the log file?
|
||||
logfile="/var/log/sshbackup.log"
|
||||
#sourcefile="/etc/sshbackup.lst"
|
||||
|
||||
sshkeyfile="$HOME/.ssh/id_rsa"
|
||||
|
||||
|
||||
# **** function definitions ****
|
||||
|
||||
bashtrap()
|
||||
{
|
||||
|
||||
echo
|
||||
echo "CTRL+C detected."
|
||||
echo "commiting suicide."
|
||||
exit 1
|
||||
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
|
||||
echo
|
||||
echo "usage: sshbackup <options>"
|
||||
echo
|
||||
echo "OPTIONS:"
|
||||
echo " -h, --help show this message"
|
||||
echo " -v, --version show version information"
|
||||
echo
|
||||
|
||||
}
|
||||
|
||||
version()
|
||||
{
|
||||
|
||||
echo
|
||||
echo "sshbackup"
|
||||
echo
|
||||
echo -e "vesion: \033[1;37m$version\033[0m"
|
||||
echo "author: $author"
|
||||
echo
|
||||
|
||||
}
|
||||
|
||||
amiroot()
|
||||
{
|
||||
if [ "$USER" != "root" ]; then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
preflight()
|
||||
{
|
||||
|
||||
if [ -r $sshkeyfile ]; then
|
||||
:
|
||||
else
|
||||
echo "error: ssh keyfile not found in $sshkeyfile. aborting mission."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
deploy()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#pulling files through ssh (actual backup process)
|
||||
sshbackup()
|
||||
{
|
||||
|
||||
if [ $(amiroot; echo $?) -ne 0 ]; then
|
||||
echo "error: this script must be run with root privileges. aborting mission."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
preflight
|
||||
|
||||
local sourcefile=$1
|
||||
|
||||
# reading sources config file (line by line)
|
||||
while read line; do
|
||||
|
||||
# find first letter
|
||||
local fletter=${line:0:1}
|
||||
|
||||
if [ -z $fletter ]; then
|
||||
#skip line it's empty
|
||||
:
|
||||
|
||||
elif [ $fletter = "#" ]; then
|
||||
#skip line it's a comment
|
||||
:
|
||||
|
||||
else
|
||||
#creating needed vars
|
||||
local server=$(echo "$line" | awk '{print $1}')
|
||||
local sourcepath=$(echo "$line" | awk '{print $2}')
|
||||
local destpath=$(echo "$line" | awk '{print $3}')
|
||||
local versions=$(echo "$line" | awk '{print $4}')
|
||||
|
||||
#creating optional vars
|
||||
local speed=$(echo "$line" | awk '{print $5}')
|
||||
|
||||
#check for speed limit
|
||||
if [ -z $speed ]; then
|
||||
#no speed limit provided in config
|
||||
local cmdopt="$options"
|
||||
else
|
||||
#adding speed limit to rsync options
|
||||
local cmdopt="$options --bwlimit=$speed"
|
||||
fi
|
||||
|
||||
#move existing versions
|
||||
local num=$versions
|
||||
while [ -d "$destpath/0" ]; do
|
||||
if [ -d "$destpath/$num" ]; then
|
||||
mv $destpath/$num $destpath/$((num+1))
|
||||
if [ $? != 0 ]; then
|
||||
echo "error - could not move version $num to version $((num+1))"
|
||||
fi
|
||||
fi
|
||||
let num--
|
||||
done
|
||||
|
||||
#create destpath if not existing
|
||||
mkdir -p $destpath/0
|
||||
|
||||
#add link-dest option
|
||||
if [ -d $destpath/1 ]; then
|
||||
#existing
|
||||
local cmdopt="$cmdopt --link-dest=$destpath/1"
|
||||
fi
|
||||
|
||||
#create connectionstring
|
||||
local constring="$server:$sourcepath"
|
||||
|
||||
|
||||
#get the MB to transfer
|
||||
#test=$(($(rsync -vrl --no-motd --dry-run --stats david@10.1.2.4:/srv/storage/david/videos /home/david/ | grep "Total transferred file size" | awk '{print $5}' | grep -e '[0-9]')/1000000))
|
||||
|
||||
#run rsync
|
||||
echo "[$(date '+%Y%m%d%H%M')] starting rsync job: $server:$sourcepath" >> $logfile
|
||||
$localcmd $cmdopt -e "ssh -q -i $sshkeyfile" --rsync-path="$remotecmd" $constring $destpath/0
|
||||
if [ $? = "0" ]; then
|
||||
echo "[$(date '+%Y%m%d%H%M')] rsync job successfully finished: $server:$sourcepath" >> $logfile
|
||||
else
|
||||
echo "[$(date '+%Y%m%d%H%M')] rsync job unsuccessful: $server:$sourcepath" >> $logfile
|
||||
echo "error: rsync job unsuccessful: $server:$sourcepath"
|
||||
fi
|
||||
|
||||
#removing obsolet version(s)
|
||||
#TODO: remove higher versions if versionsnumber in sourcefile is lower
|
||||
if [ -d "$destpath/$((versions+1))" ]; then
|
||||
rm -rf $destpath/$((versions+1))
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
#count lines for debug output
|
||||
let linecount++
|
||||
|
||||
done < $sourcefile
|
||||
|
||||
}
|
||||
|
||||
|
||||
# **** start of script ****
|
||||
|
||||
#initialize bashtrap
|
||||
trap bashtrap INT
|
||||
|
||||
#check dependencies/environment
|
||||
#install dependencies on debian, ubuntu, arch, fedora, redhat, centos
|
||||
#develope a os_check_install_dependencies_function for different distros
|
||||
#will be practical for all kinds of scripts
|
||||
#dependencies: rsync, telnet, bash, sudo
|
||||
|
||||
#option handler
|
||||
if [ -z $1 ]; then
|
||||
echo "no sourcefile given. exiting."
|
||||
usage
|
||||
exit 1
|
||||
elif [ -r $1 ]; then
|
||||
sshbackup $1
|
||||
exit $?
|
||||
elif [ $1 == "--help" ] || [ $1 == "-h" ]; then
|
||||
usage
|
||||
exit 0
|
||||
elif [ $1 == "--version" ] || [ $1 == "-v" ]; then
|
||||
version
|
||||
exit 0
|
||||
else
|
||||
echo "unknown option given or sourcefile not readable. exiting."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# **** end of script ****
|
|
@ -1,329 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
# ************************************* #
|
||||
# #
|
||||
# sshbackup #
|
||||
# #
|
||||
# ************************************* #
|
||||
|
||||
# **** config section ****
|
||||
version="0.3"
|
||||
author="david@socialnerds.org"
|
||||
|
||||
configfile="$HOME/.sshbackup"
|
||||
sourcefile=""
|
||||
#rsync options.
|
||||
rsyncoptions="-pogEthrzl --numeric-ids --no-motd"
|
||||
#dotglob option removes bug while rsyncing folder with no visible files in it.
|
||||
remotecmd="shopt -s dotglob; /usr/bin/sudo /usr/bin/rsync"
|
||||
localcmd="/usr/bin/rsync"
|
||||
|
||||
#where should i write the log file?
|
||||
logfile="/var/log/sshbackup.log"
|
||||
|
||||
sshkeyfile="$HOME/.ssh/id_rsa"
|
||||
|
||||
config=0
|
||||
sshkey=0
|
||||
deploy=0
|
||||
list=0
|
||||
options=$*
|
||||
|
||||
|
||||
# **** function definitions ****
|
||||
bashtrap()
|
||||
{
|
||||
|
||||
echo
|
||||
echo "CTRL+C detected."
|
||||
echo "commiting suicide."
|
||||
exit 1
|
||||
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
|
||||
echo
|
||||
echo "usage: sshbackup <options> source destination [versions]"
|
||||
echo "source/destination example: [[user@]server:]/path/to/files"
|
||||
echo
|
||||
echo "OPTIONS:"
|
||||
echo " -h, --help show this message"
|
||||
echo " -v, --version version information"
|
||||
echo " -c, --config <configfile> alternate config file"
|
||||
echo " -l, --list <listfile> list of sources and destinations"
|
||||
echo " -s, --sshkey <sshkeyfile> alternate sshkeyfile"
|
||||
echo " -d, --deploy <remote machine> deploy remote settings"
|
||||
echo
|
||||
|
||||
}
|
||||
|
||||
version()
|
||||
{
|
||||
|
||||
echo
|
||||
echo -e "vesion: \033[1;37m$version\033[0m"
|
||||
echo "author: $author"
|
||||
echo
|
||||
|
||||
}
|
||||
|
||||
preflight()
|
||||
{
|
||||
|
||||
#amiroot
|
||||
if [ $(whoami) != "root" ]; then
|
||||
#echo "no root privileges available. continuing without."
|
||||
:
|
||||
fi
|
||||
|
||||
if [ -z $sourcepath ]; then
|
||||
echo "aborting mission. no source path given."
|
||||
exit 1
|
||||
elif [ -z $destinationpath ]; then
|
||||
echo "aborting mission. no destination path given."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -r $sshkeyfile ]; then
|
||||
#echo "sshkeyfile found"
|
||||
:
|
||||
else
|
||||
#am i being run by cron?
|
||||
tty -s
|
||||
if [ $? -eq 0 ]; then
|
||||
#echo "i am running in interactive mode"
|
||||
echo "you do not have a sshkey configured."
|
||||
echo -e "do you want to create a new keypair? [y] \c"
|
||||
read answer
|
||||
if [ -z $answer ]; then
|
||||
answer="y"
|
||||
fi
|
||||
if [ $answer == "y" ] || [ $answer == "Y" ]; then
|
||||
#create keypair
|
||||
:
|
||||
else
|
||||
#continue without sshkey
|
||||
:
|
||||
fi
|
||||
else
|
||||
echo "aborting mission. no sshkey found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
}
|
||||
|
||||
#work in progress
|
||||
deploy()
|
||||
{
|
||||
|
||||
backupuser="sshbackup"
|
||||
publickey="/home/david/.ssh/id_rsa.pub"
|
||||
publickey=$(cat $publickey)
|
||||
|
||||
# ask if to continue when run as root
|
||||
if [ $USER == "root" ]; then
|
||||
echo "there is no need to run this script with root privileges."
|
||||
echo "however, it is possible if you wish to do so anyway."
|
||||
echo -e "do you want to continue as root [y/n]? \c"
|
||||
read answer
|
||||
if [ $answer == "y" ] || [ $answer == "Y" ]; then
|
||||
:
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
answer=""
|
||||
|
||||
echo -e "remote admin [$USER]: \c"
|
||||
read answer
|
||||
if [ -z $answer ]; then
|
||||
remoteadmin=$USER
|
||||
else
|
||||
remoteadmin=$answer
|
||||
fi
|
||||
answer=""
|
||||
|
||||
echo -e "backupuser [$backupuser]: \c"
|
||||
read answer
|
||||
if [ -z $answer ]; then
|
||||
:
|
||||
else
|
||||
backupuser=$answer
|
||||
fi
|
||||
answer=""
|
||||
|
||||
while [ -z $remotemachine ]; do
|
||||
if [ -z $1 ]; then
|
||||
echo -e "remote ip or hostname: \c"
|
||||
read answer
|
||||
remotemachine=$answer
|
||||
else
|
||||
remotemachine=$1
|
||||
fi
|
||||
done
|
||||
answer=""
|
||||
|
||||
|
||||
cat /etc/passwd | grep -e ^$backupuser
|
||||
if [ \$? -eq 0 ]; then
|
||||
echo "error: $backupuser already exists on $remotemachine"
|
||||
echo "info: aborting mission."
|
||||
exit 1
|
||||
else
|
||||
echo "info: attempting to create user: $backupuser"
|
||||
useradd -m -d /home/$backupuser $backupuser
|
||||
if [ \$? -eq 0 ]; then
|
||||
mkdir /home/$backupuser/.ssh
|
||||
echo $publickey >> /home/$backupuser/.ssh/authorized_keys
|
||||
if [ \$? -eq 0 ]; then
|
||||
echo "info: user created and public key added to authorized hosts."
|
||||
else
|
||||
echo "error: user created but adding the public key to authorized hosts returned a non-zero value. aborting mission."
|
||||
fi
|
||||
else
|
||||
echo "error: useradd returned a non-zero value. aborting mission."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
sshbackup()
|
||||
{
|
||||
|
||||
#debugging
|
||||
#echo "source: $sourcepath"
|
||||
#echo "destination: $destinationpath"
|
||||
#echo "versions: $versions"
|
||||
#echo "sshkey: $sshkeyfile"
|
||||
#echo "config: $configfile"
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
# **** start of script ****
|
||||
|
||||
#initialize bashtrap
|
||||
trap bashtrap INT
|
||||
|
||||
# **** option handler ****
|
||||
if [ -z $1 ]; then
|
||||
echo "no options given. aborting mission."
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for option in $options; do
|
||||
case "$option" in
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
-v|--version)
|
||||
version
|
||||
exit 0
|
||||
;;
|
||||
-c|--config)
|
||||
config=1
|
||||
;;
|
||||
-l|--list)
|
||||
list=1
|
||||
;;
|
||||
-s|--sshkey)
|
||||
sshkey=1
|
||||
;;
|
||||
-d|--deploy)
|
||||
deploy=1
|
||||
;;
|
||||
*)
|
||||
if [ $config -eq 1 ]; then
|
||||
if [ -r $option ]; then
|
||||
configfile=$option
|
||||
config=0
|
||||
else
|
||||
echo "aborting mission. cannot read configfile. [$option]"
|
||||
exit 1
|
||||
fi
|
||||
elif [ $sshkey -eq 1 ]; then
|
||||
if [ -r $option ]; then
|
||||
sshkeyfile=$option
|
||||
sshkey=0
|
||||
else
|
||||
echo "aborting mission. cannot read sshkeyfile. [$option]"
|
||||
exit 1
|
||||
fi
|
||||
elif [ $deploy -eq 1 ]; then
|
||||
remotemachine=$option
|
||||
deploy=0
|
||||
elif [ $list -eq 1 ]; then
|
||||
if [ -r $option ]; then
|
||||
listfile=$option
|
||||
list=0
|
||||
else
|
||||
echo "aborting mission. cannot read listfile. [$option]"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if [[ $option =~ ^-.* ]]; then
|
||||
echo "aborting mission. unknown option given. [$option]"
|
||||
usage
|
||||
exit 1
|
||||
#TODO: what if source or dest is a number?
|
||||
elif [ -z "${option//[0-9]/}" ]; then
|
||||
if [ -z $versions ]; then
|
||||
versions=$option
|
||||
fi
|
||||
else
|
||||
if [ -z $sourcepath ]; then
|
||||
sourcepath=$option
|
||||
else
|
||||
if [ -z $destinationpath ]; then
|
||||
destinationpath=$option
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -r "$configfile" ]; then
|
||||
source $configfile
|
||||
fi
|
||||
|
||||
#read list if listfile is given
|
||||
if [ -r "$listfile" ]; then
|
||||
while read line; do
|
||||
# find first letter
|
||||
fletter=${line:0:1}
|
||||
if [ -z $fletter ]; then
|
||||
#skip line it's empty
|
||||
:
|
||||
elif [ $fletter = "#" ]; then
|
||||
#skip line it's a comment
|
||||
:
|
||||
else
|
||||
#creating variables
|
||||
sourcepath=$(echo "$line" | awk '{print $1}')
|
||||
destinationpath=$(echo "$line" | awk '{print $2}')
|
||||
versions=$(echo "$line" | awk '{print $3}')
|
||||
preflight
|
||||
sshbackup
|
||||
fi
|
||||
done < $listfile
|
||||
else
|
||||
preflight
|
||||
sshbackup
|
||||
fi
|
||||
|
||||
|
||||
# **** end of script ****
|
||||
exit 0
|
184
sshsudo
184
sshsudo
|
@ -1,184 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# sshsudo: 1.0
|
||||
# Author: jiwu.liu@gmail.com
|
||||
#
|
||||
# The script executes sudo command on one or more remote computers.
|
||||
# Its arguments are the names to remote sudoers and remote computers.
|
||||
# The script read the password from the standard input, which should
|
||||
# be the same for all sudoer accounts. No password is explicitly shown
|
||||
# in the terminal or logged to files.
|
||||
# If the command is a local shell script, use '-r' to copy it to
|
||||
# the remote computers to execute. A temporary script file will be
|
||||
# automatically created for this purpose.
|
||||
#
|
||||
#
|
||||
# TO DO: It can not execute a command that use the shell special charaters
|
||||
# on the remote computer, such as & ; ! *, because all arguments
|
||||
# are wrapped with ''. That means, all special characters have only
|
||||
# literal meanings. In the case when they are needed, use a script
|
||||
# instead of a command.
|
||||
#
|
||||
# Example:sshsudo foo@bar.net apt-get check
|
||||
# sshsudo -r foo@bar.net myscript.sh
|
||||
|
||||
|
||||
usage()
|
||||
{
|
||||
local ProgName=$1;
|
||||
echo "Usage: $ProgName -r -v [-u user] AccountList Command [Arguments]"
|
||||
echo " -u Set the default user unless it is given within remote account list"
|
||||
echo " -r Copy the command(usually the path to local script) to remote computers before execution"
|
||||
echo " -v Verbose output"
|
||||
echo " AccountList: [user1@]computer1,[user2@]computer2,[user3@]computer3,..."
|
||||
echo " or the name to file which contains accounts(user@computer) in separate lines"
|
||||
echo " Command: The Command/Script to be executed"
|
||||
echo " Arguments: All arguments to be passed to command."
|
||||
}
|
||||
|
||||
pipewrap()
|
||||
{
|
||||
# This function reads in the input from a terminal and output the same.
|
||||
# The only purpose is to insert PASSWORD for "sudo -S" command.
|
||||
# After initially insert the password, it simply copy input from terminal
|
||||
# and send it to ssh command directly
|
||||
echo $1 # which is password
|
||||
local lockFile=$2;
|
||||
while true; do
|
||||
# The function will exit when output pipe is closed,
|
||||
if [ ! -e $lockFile ]; then
|
||||
return 0
|
||||
fi
|
||||
# i.e., the ssh
|
||||
read -t 1 line
|
||||
if [ $? -eq 0 ]; then
|
||||
# successfully read
|
||||
echo $line
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
runsudo ()
|
||||
{
|
||||
# receive its arguments
|
||||
local ACCOUNT=$1;
|
||||
local PASSWORD=$2;
|
||||
local COMMAND=$3;
|
||||
local ARGUMENTS=$4;
|
||||
local DEFAULTUSER=$5;
|
||||
local COPY=$6;
|
||||
local VERBOSE=$7;
|
||||
|
||||
# Parse account which has the form user@computer.domain
|
||||
local REMOTEUSER=${ACCOUNT%%@*}
|
||||
local REMOTECOMPUTER=${ACCOUNT#*@}
|
||||
local REMOTESCRIPT=
|
||||
local REMOTECOMMAND=$COMMAND
|
||||
if [ $REMOTEUSER = $REMOTECOMPUTER ]; then
|
||||
# There is no @, i.e., only computer name is given
|
||||
REMOTEUSER=$DEFAULTUSER
|
||||
fi
|
||||
echo =========================${REMOTEUSER}@$REMOTECOMPUTER: sudo $COMMAND $ARGUMENTS
|
||||
if [ $COPY -ne 0 ]; then
|
||||
# Make a script + seconds since 1970-01-01
|
||||
REMOTESCRIPT=/tmp/$COMMAND`date +%s`
|
||||
if [ $VERBOSE -ne 0 ]; then
|
||||
echo $REMOTECOMPUTER: Secure copy \"$COMMAND\" to \"$REMOTESCRIPT\"
|
||||
fi
|
||||
# Copy to remote computer. Quote target name on the remote computer for script name
|
||||
# that contains " "
|
||||
sshpass -p "$PASSWORD" scp "$COMMAND" "$REMOTEUSER@$REMOTECOMPUTER:'$REMOTESCRIPT'"
|
||||
REMOTECOMMAND=$REMOTESCRIPT
|
||||
fi
|
||||
|
||||
# Assume we are lucky, result is fine.
|
||||
local RES=DONE
|
||||
# Invalidate the sudo timestamp. Simplify the situation. Henceforth sudo always ask for a password
|
||||
sshpass -p "$PASSWORD" ssh "$REMOTEUSER@$REMOTECOMPUTER" "sudo -K"
|
||||
|
||||
# Use lock file to inform pipewrap function to exit.
|
||||
local lockFile=`mktemp`
|
||||
eval pipewrap '$PASSWORD' '$lockFile' | (sshpass -p "$PASSWORD" ssh "$REMOTEUSER@$REMOTECOMPUTER" "sudo -S '$REMOTECOMMAND' $ARGUMENTS"; rm "$lockFile")
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
RES=FAILED
|
||||
fi
|
||||
if [ $COPY -ne 0 ]; then
|
||||
sshpass -p $PASSWORD ssh "$REMOTEUSER@$REMOTECOMPUTER" rm \'$REMOTESCRIPT\'
|
||||
if [ $VERBOSE -ne 0 ]; then
|
||||
echo Remove temporary script \"$REMOTESCRIPT\" at [$REMOTECOMPUTER]
|
||||
fi
|
||||
fi
|
||||
echo ----------------------------------${RES}!!----------------------------------------
|
||||
}
|
||||
|
||||
|
||||
#=====================================Main Script========================================
|
||||
#
|
||||
# Set default values for variables
|
||||
COMMAND=
|
||||
ARGUMENTS=
|
||||
COPY=0
|
||||
VERBOSE=0
|
||||
ACCOUNTLIST=
|
||||
DEFAULTUSER=$USER
|
||||
|
||||
# Parse the command line arguments with '-'
|
||||
while getopts u:hrv o ; do
|
||||
case "$o" in
|
||||
[?]) usage $0
|
||||
exit 1;;
|
||||
h) usage $0
|
||||
exit 0;;
|
||||
u) DEFAULTUSER=$OPTARG;;
|
||||
v) VERBOSE=1;;
|
||||
r) COPY=1;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Read the rest command line arguments
|
||||
if [ $(($#-$OPTIND+1)) -lt 2 ]; then
|
||||
echo Error: Account list and command have to be in the arguments
|
||||
usage $0
|
||||
exit 4
|
||||
fi
|
||||
|
||||
shift $(($OPTIND-1))
|
||||
ACCOUNTLIST=$1
|
||||
shift
|
||||
COMMAND=$1
|
||||
shift
|
||||
for PARAM; do
|
||||
ARGUMENTS=$ARGUMENTS\'$PARAM\'" "
|
||||
done
|
||||
|
||||
# Check the validity of the script command if remote copy is needed
|
||||
if [ $COPY -ne 0 ]; then
|
||||
if [ ! -e "$COMMAND" ]; then
|
||||
echo \"$COMMAND\" does not exist.
|
||||
exit 3
|
||||
fi
|
||||
if [ ! -x "$COMMAND" ]; then
|
||||
echo \"$COMMAND\" can not be executed.
|
||||
exit 3
|
||||
fi
|
||||
fi
|
||||
|
||||
# Read in the password from the STDIN
|
||||
read -s -p "Please enter your password:" PASSWORD
|
||||
echo
|
||||
|
||||
# Start running
|
||||
if [ -e $ACCOUNTLIST ]; then # read accounts from a file
|
||||
for ACCOUNT in `cat $ACCOUNTLIST`; do
|
||||
runsudo "$ACCOUNT" "$PASSWORD" "$COMMAND" "$ARGUMENTS" "$DEFAULTUSER" "$COPY" "$VERBOSE";
|
||||
done
|
||||
|
||||
else # ACCOUNTLIST is a comma separated list of user@computer strings.
|
||||
# Change the internal separation field.
|
||||
IFS=,
|
||||
for ACCOUNT in $ACCOUNTLIST; do
|
||||
runsudo "$ACCOUNT" "$PASSWORD" "$COMMAND" "$ARGUMENTS" "$DEFAULTUSER" "$COPY" "$VERBOSE";
|
||||
done
|
||||
fi
|
||||
#EOF
|
Reference in New Issue