Created
February 15, 2013 19:48
-
-
Save lifning/4962936 to your computer and use it in GitHub Desktop.
A backup script I wrote as a system administration course assignment in 2011.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
# print usage information if -h flag is passed | |
usage() | |
{ | |
cat 1>&2 <<EOF | |
usage: $0 [-hv] [-i instance] [-m method] [-t tag] -d dir | |
-h Print a usage statement and exit. | |
-v Be verbose. | |
-e recipient Encrypt the data for the specified recipient. | |
-i instance Attach the volume in question to the given instance. | |
-m (dd|rsync) Use the given method to perform the backup. | |
-t tag Use the volume with the given tag. | |
EOF | |
} | |
VERBOSE=0 | |
ENCRYPT=cat | |
INSTANCE= | |
TERMINATE=0 | |
# default value of METHOD for when -m isn't specified: | |
METHOD=dd | |
# default value of TAG for when -t isn't specified: | |
TAG=ec2-backup | |
DIRECTORY= | |
# parse command line options using getopts | |
while getopts "hve:i:m:t:d:" OPTION | |
do | |
case $OPTION in | |
h) usage ; exit ;; | |
v) VERBOSE=1 ;; | |
e) | |
if [ "${ENCRYPT}" = "cat" ] ; then | |
ENCRYPT="gpg -e" | |
fi | |
ENCRYPT="$ENCRYPT -r $OPTARG" ;; | |
i) INSTANCE=$OPTARG ;; | |
m) | |
case $OPTARG in | |
dd) METHOD=dd ;; | |
rsync) METHOD=rsync ;; | |
*) # exit with an error code if an invalid method is given | |
echo $0: "invalid -m value (should be dd or rsync)" 1>&2 | |
exit 2 | |
;; | |
esac | |
;; | |
t) TAG=$OPTARG ;; | |
d) | |
if [ -d $OPTARG ] ; then | |
DIRECTORY=$OPTARG | |
else | |
# exit with an error code if argument to -d is not a directory | |
echo $0: $OPTARG" is not a valid directory" 1>&2 | |
exit 3 | |
fi | |
;; | |
# show usage and exit with an error code if invalid arguments given | |
# note: getopts already shows a helpful message before "usage" is called | |
*) usage ; exit 1 ;; | |
esac | |
done | |
# don't continue if a directory wasn't specified! | |
if [ x"${DIRECTORY}" = x"" ] ; then | |
echo $0: "a directory must be given with '-d directory'" 1>&2 | |
exit 4 | |
fi | |
# handling verbosity in a somewhat clever way | |
VERBDIRECT=true | |
if [ $VERBOSE = 1 ] ; then | |
VERBDIRECT=cat | |
fi | |
# some encryption-related details | |
if [ "${ENCRYPT}" != "cat" ] ; then | |
# don't continue if trying to use gpg and rsync together! | |
if [ $METHOD != dd ] ; then | |
echo $0: "must use method 'dd' when using PGP encryption" | |
exit 10 | |
else | |
echo "encrypting using command: $ENCRYPT"|$VERBDIRECT | |
fi | |
fi | |
# get size of directory in GB | |
SIZE=$(du -sBGB $DIRECTORY | awk '{print $1}' | sed 's/[^0-9]//g') | |
# add 1GiB of size to "round up" / for overhead | |
SIZE=$(expr $SIZE + 1) | |
# availability zone (needs to be same between instance and volume) | |
ZONE= | |
if [ x"${INSTANCE}" != x"" ] ; then | |
ZONE=$(ec2din | grep "^INSTANCE.$INSTANCE.*running" | awk '{print $11}') | |
fi | |
if [ x"${ZONE}" = x"" ] ; then | |
ZONE=$(ec2-describe-availability-zones | head -1 | awk '{print $2}') | |
fi | |
# get information about existing volume | |
OUTPUT=$(ec2dvol -F "tag-key=$TAG" | grep '^VOLUME.*available' | head -1) | |
VOLUME=$(echo $OUTPUT | awk '{print $2}') | |
VOLSIZE=$(echo $OUTPUT | awk '{print $3}') | |
VOL_JUST_CREATED=0 | |
# does volume exist? if not, create volume | |
if [ x"${VOLUME}" = x"" ] ; then | |
[ $VERBOSE = 1 ] && echo "creating volume in $ZONE" | |
# the value for -z is a hack, don't know how to make it not required... | |
VOLUME=$(ec2addvol -s $SIZE -z $ZONE | awk '{print $2}') | |
if [ $? != 0 ] ; then | |
echo $0: "couldn't create volume." 1>&2 | |
exit 5 | |
fi | |
# tag the new volume, or die trying | |
ec2tag -t $TAG $VOLUME |$VERBDIRECT || exit 6 | |
VOL_JUST_CREATED=1 | |
# if the existing volume isn't big enough, throw an error! | |
elif [ "$VOLSIZE" -lt "$SIZE" ] ; then | |
echo $0: "specified volume is too small! $VOLSIZE < $SIZE" 1>&2 | |
exit 7 | |
else | |
[ $VERBOSE = 1 ] && echo "using $VOLUME" | |
fi | |
# if no instance specified at command line, start instance | |
if [ x"${INSTANCE}" = x"" ] ; then | |
EC2_RUN_INSTANCES_FLAGS=$EC2_RUN_INSTANCES_FLAGS" -z $ZONE" | |
OUTPUT=$(ec2-start-instance) | |
if [ $? != 0 ] ; then | |
echo $0: "couldn't create instance to attach volume." 1>&2 | |
exit 8 | |
fi | |
INSTANCE=$(echo $OUTPUT | awk '{print $1}') | |
HOSTNAME=$(echo $OUTPUT | awk '{print $2}') | |
TERMINATE=1 | |
# hackish! give the machine some time to start up services, especially ssh | |
sleep 20 | |
else | |
# otherwise, just get its host name | |
HOSTNAME=$(ec2din|grep "^INSTANCE.$INSTANCE.*running"|awk '{print $4}') | |
if [ x"${HOSTNAME}" = x"" ] ; then | |
echo $0: "no such instance!" 1>&2 | |
exit 9 | |
fi | |
fi | |
# attach volume to instance, or die trying | |
ec2-attach-volume -i $INSTANCE -d /dev/sdh $VOLUME |$VERBDIRECT || exit 10 | |
# give it some time to attach... | |
sleep 20 | |
# do the backup by whatever method was specified | |
if [ $METHOD = rsync ] ; then | |
# find out if we need to format | |
if [ $VOL_JUST_CREATED = 1 ] ; then | |
ssh $HOSTNAME "yes | mkfs /dev/sdh" 2>&1 |$VERBDIRECT | |
fi | |
# mount the drive, sync the files, and unmount | |
ssh $HOSTNAME "mkdir -p /mnt/ec2backup" 2>&1 |$VERBDIRECT | |
ssh $HOSTNAME "mount /dev/sdh /mnt/ec2backup" 2>&1 |$VERBDIRECT | |
rsync -aq $DIRECTORY $HOSTNAME:/mnt/ec2backup 2>&1 |$VERBDIRECT | |
ssh $HOSTNAME "umount /dev/sdh" 2>&1 |$VERBDIRECT | |
else | |
tar c $DIRECTORY | $ENCRYPT | ssh $HOSTNAME "dd of=/dev/sdh" 2>&1 |$VERBDIRECT | |
fi | |
ec2-detach-volume $VOLUME |$VERBDIRECT | |
# terminate instance if we started it in this script | |
if [ $TERMINATE = 1 ] ; then | |
ec2-terminate-instances $INSTANCE |$VERBDIRECT | |
fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# print usage information if -h flag is passed | |
usage() | |
{ | |
cat 1>&2 <<EOF | |
usage: $0 [-hv] [-a ami] | |
-a AMI Start an instance of the given AMI. | |
-h Print a usage statement and exit. | |
-v Be verbose. | |
EOF | |
} | |
# default value of AMI for when -a isn't specified: | |
AMI=ami-b232d0db | |
VERBOSE=0 | |
# parse command line options using getopts | |
while getopts "hva:" OPTION | |
do | |
case $OPTION in | |
h) usage ; exit ;; | |
v) VERBOSE=1 ;; | |
a) AMI=$OPTARG ;; | |
# show usage and exit with an error code if invalid arguments given | |
# note: getopts already shows a helpful message before "usage" is called | |
*) usage ; exit 1 ;; | |
esac | |
done | |
# for the sake of not breaking 80 characters in width, rename this var... | |
EC2_RIF=$EC2_RUN_INSTANCES_FLAGS | |
# start the instance and get the instance ID | |
INSTANCE=$(ec2run $AMI $EC2_RIF | grep '^INSTANCE' | awk '{print $2}') | |
if [ .$INSTANCE != . ] ; then | |
# the first part of the output, the instance id. don't output a newline yet. | |
echo -n "$INSTANCE " | |
# check the status of the machine until it is running and has a host | |
STATUS=pending | |
while [ .$STATUS == .pending ] ; do | |
STATUS=$(ec2din | grep "^INSTANCE.$INSTANCE" | awk '{print $4}') | |
[ $VERBOSE == 1 ] && echo "waiting for instance to be ready..." 1>&2 | |
sleep 5 | |
done | |
# the fourth thing in the output of ec2din, which was its status before, | |
# just happens to be the position of the hostname! lucky us. | |
echo $STATUS | |
else | |
echo $0: "an error occurred while starting the instance." 1>&2 | |
exit 2 | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment