Backup Tapes
Giorgos Keramidas
keramida at ceid.upatras.gr
Tue Jun 19 14:31:42 EEST 2007
Έβαλα αριθμούς στις γραμμές παρακάτω, για να είναι πιο εύκολο να
αναφερθεί κανείς σε πολλές μαζί.
1 #!/bin/sh
2
3 #######################################################################
4 #
5 # Backup Script. If used without any argument a full
6 # or incremental backup will be done depending on the day
7 # ( 1st full, others incremental). If used with an argument
8 # ( full or incr ) you can force type of backup.
9 #
10 #######################################################################
Τα 'όμορφα blocks' στα σχόλια είναι πολύ 'κουραστικά για το μάτι'
μερικές φορές. Συνήθως αρκεί κάτι σαν:
#!/bin/sh
#
# Backup script for host `jenna'.
# Copyright (C) 2007 Yiannis Yiakoumis.
Αν θέλεις να φαίνεται και 'usage' στο πάνω μέρος του script, καλό είναι
να ακολουθεί ένα στυλ περίπου σαν αυτό που έχουν τα συνηθισμένα UNIX
manpages:
#!/bin/sh
#
# Backup script for host `jenna'.
# Copyright (C) 2007 Yiannis Yiakoumis.
#
# SYNOPSIS
# backup.sh [ mode ]
#
# DESCRIPTION
# This script can be used to save backup copies of important files,
# like MySQL databases, web server log files, etc.
#
# When run without options, the script will take a full backup of all
# the files considered ``important'' if the current day is the first
# day of the month. Otherwise an incremental backup will be saved.
#
# When run with a ``mode'' argument, the values accepted for ``mode''
# are the following:
#
# full Full backup of all files.
#
# incr Incremental backup of only the files modified since
# the last time we got a full backup.
Μετά το script έχει:
12 HOME_BACKUP=/home
13 ETC_BACKUP=/etc
14 LOGS_BACKUP=/var/log
15 BACKUP_DIR=/root/backup
16 TMP=$BACKUP_DIR/tmp
17
18 mkdir $TMP
Οταν χρησιμοποιείς shell variables σε expanded μορφή (όπως το
$BACKUP_DIR παραπάνω), είναι καλή ιδέα να γράφεις κάτι σαν:
TMP="${BACKUP_DIR}/tmp"
έτσι είναι πιο "ασφαλές" ότι δε θα γίνει expand στο λάθος μέρος του
string.
Το $TMP παραείναι γενικό σαν όνομα :-(
Τα κεφαλαία είναι λίγο σαν να φωνάζεις μόνιμα.
Η λίστα με τα backup directories είναι επίσης λίγο «άσχημο» που είναι
ένα μάτσο shell μεταβλητές. Θα μπορούσε να είναι μόνο μία:
# List of directories which we save in backup tarballs.
FLIST='/home /etc /var/log'
20 DATE=`date +%Y_%m_%d`
Τα backquotes είναι για να θέσει το shell σου ως τιμή της $DATE την
έξοδο της εντολής, αλλά τα arguments της 'date' command είναι εντελώς
unquoted και μπορεί να γίνουν expand με «μη αναμενόμενο» τρόπο. Επίσης
το $DATE που έχεις εδώ είναι μια χαρά ως «filename», αλλά τα underscores
είναι ελαφρώς κιτς ως διαχωριστικά και δε μπορείς να πάρεις περισσότερα
από ένα backup images σε μια μέρα. Εγώ θα έβαζα τουλάχιστον και την
ώρα, και τελείες ως separators, με λίγο διαφορετικό όνομα στη μεταβλητή:
STAMP=`date '+%Y.%m.%d.%H'`
22 echo "DAILY BACKUP STARTS @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ " > $BACKUP_DIR/backup-log.txt
23 echo $DATE >> backup-log.txt
Αντί να θυμάσαι κάθε φορά πως λεγόταν το log file θα μπορούσες να το
σώσεις σε μια μεταβλητή, π.χ. με όνομα LOGFILE. Ακόμα καλύτερα, μπορείς
να φτιάξεις μια shell function με όνομα log() που γράφει στο LOGFILE,
έτσι που η «γνώση» του pathname για το log file να είναι σε ένα και
μοναδικό σημείο. Αν αργότερα αλλάξεις γνώμη για το πώς θα λέγεται το
log file, δε θα χρειάζεται να αλλάξεις 100 σημεία αλλά ένα και μόνο.
Με τη χρήση μιας log() function μπορείς να κάνεις και άλλα «όμορφα»
πράγματα, όπως π.χ. time-stamped log entries, κάπως έτσι:
log()
{
_now="`date '+%Y-%m-%d %H:%M:%S'` "
if test -n "${LOGFILE}" ; then
echo "${_now}$*" >> "${LOGFILE}"
else
# No log file; send log output to stderr.
echo "${_now}$*" >&2
fi
}
Τότε θα μπορείς να γράψεις πράγματα όπως:
# Setup of backup environment.
BDIR='/root/backup'
LOGFILE="$BDIR/backup.log"
log "Backup at ${BDIR} starting."
runbackup
log "Backup at ${BDIR} finished."
Με μια σχετικά πιο 'modular' συνάρτηση με όνομα runbackup(), το παραπάνω
μπορεί να είναι ΟΛΟΣ ο κύριος κορμός του backpu script! Δεν είναι πολύ
πιο ευανάγνωστο έτσι;
25 # If called with argument force backup type, otherwise check date to decide
26
27 if [ "$1" ]; then
28 if [ $1 = full ]; then
29 echo "Forcing Full Backup" >> $BACKUP_DIR/backup-log.txt
30 BACKUP_TYPE=FULL
31 elif [ $1 = incr ]; then
32 echo "Forcing Incremental Backup" >> $BACKUP_DIR/backup-log.txt
33 BACKUP_TYPE=INCR
34 fi
35 else
36 echo "Checking Backup Type..." >> $BACKUP_DIR/backup-log.txt
37 if [ `date +%d` = 01 ]; then
38 echo "Going for a Full Backup" >> $BACKUP_DIR/backup-log.txt
39 BACKUP_TYPE=FULL
40 else
41 echo "Going for an Incremental Backup" >> $BACKUP_DIR/backup-log.txt
42 BACKUP_TYPE=INCR
43
44 fi
45 fi
Το παραπάνω είναι λίγο «μπερδεμένο», αλλά ας δούμε πώς μπορεί να
γίνει καλύτερο. Δε μου αρέσει τόοοσο πολύ το 'text based option'
που μπορεί να είναι 'incr' ή 'full'. Προτιμώ κάτι σαν τα -i και
-f options:
# Run in quiet, non-verbose mode by default.
VERBOSE='no'
# Full backup mode is off by default, unless today is the
# first day of the month.
FULLBACKUP='no'
if test "`date '+%d'`" = "01" ; then
FULLBACKUP='yes'
fi
# Allow command-line options to override the defaults.
set -- `getopt fiv $*`
while [ $# -gt 0 ]; do
case $1 in
-i)
FULLBACKUP='no'
;;
-f)
FULLBACKUP='yes'
;;
-v)
VERBOSE='yes'
;;
--)
shift ; break ;;
esac
shift
done
Έτσι θα μπορεί κανείς να τρέξει το backup.sh script σου με:
/root/backup.sh -f
/root/backup.sh -i
/root/backup.sh
Στην πρώτη περίπτωση θα κάνει full backup, στην άλλη όχι. Στην
τρίτη περίπτωση θα πάρει incremental backup, εκτός κι αν είναι η
πρώτη μέρα του μήνα (οπότε θα πάρει full backup).
48 # MySQL Databases & Logs( no matter if full or incr )
49 echo "->Backing up MySQL Databases..." >> $BACKUP_DIR/backup-log.txt
50 mysqldump website -u web --password=xxxx > $TMP/db_dump.sql
51 tar zcfp $TMP/logs_backup.tgz $LOGS_BACKUP
``WTF, why?''
Αν είναι να πάρεις ``incremental'' backups ή πάρε incremental
backups ή μην δίνεις αυτό το option στον χρήστη, που δε φταίει σε
τίποτα ο καημένος να νομίζει ότι θα πάρει incremental backups με
μέγεθος 2 MB, για να ανακαλύψει ότι τα 8192 MB που έχει ελεύθερα
ο δίσκος γέμισαν με full backup της MySQL!!!
Κι εδώ το `echo' αντί για `log' είναι λίγο ενοχλητικό.
Τα quotes λείπουν, και δεν ελέγχονται τα return values από τις
εντολές backup.
Καλύτερα γράψε κάτι σαν:
backup_mysql()
{
# Space-separated list of databases to backup.
dblist="website"
if test -z "${BDIR}" ; then
log "Backup dir \$BDIR is unset or empty."
return 1
fi
log "Saving MySQL dumps"
cd "${BDIR}"
if test ! -d mysql ; then
mkdir mysql
if test $? -ne 0 ; then
log "${BDIR}/mysql: cannot create directory."
return 1
fi
fi
cd mysql
for db in ${dblist} ; do
dbtmp="${db}.dump.$$"
mysqldump "${db}" -u web --password=XXXX > "${dbtmp}" && \
mv "${dbtmp}" "${db}"
if test $? -ne 0 ; then
log "mysqldump: cannot dump database ${db}"
test -f "${dbtmp}" && rm -f "${dbtmp}"
fi
done
return 0
}
Τώρα μπορείς σε οποιοδήποτε μέρος του script να γράψεις:
backup_mysql
και να πάρεις backups από όλες τις databases που έχεις ορίσει στη
λίστα $dblist στην αρχή της backup_mysql() function.
Αντίστοιχους ελέγχους χρειάζεται και σε άλλα μέρη του script, όπως:
59 # Creating tar files and metadata files for following incrementals
60 tar zcfp $TMP/home_backup.tgz $HOME_BACKUP --listed-incremental=$BACKUP_DIR/last-home-snapshot >> $BACKUP_DIR/backup-log.txt
61 tar zcfp $TMP/etc_backup.tgz $ETC_BACKUP --listed-incremental=$BACKUP_DIR/last-etc-snapshot >> $BACKUP_DIR/backup-log.txt
Τί γίνεται αν αποτύχει κάποιο tar εδώ;
65 cp $BACKUP_DIR/last-home-snapshot $TMP/home-log
66 cp $BACKUP_DIR/last-etc-snapshot $TMP/etc-log
67 tar zcfp $TMP/home_backup.tgz $HOME_BACKUP --listed-incremental=$TMP/home-log >> $BACKUP_DIR/backup-log.txt
68 tar zcfp $TMP/etc_backup.tgz $ETC_BACKUP --listed-incremental=$TMP/etc-log >> $BACKUP_DIR/backup-log.txt
κι εδώ;
71 cd $TMP
72 tar zcvf backup_webserver$DATE$BACKUP_TYPE.tar.gz home_backup.tgz etc_backup.tgz logs_backup.tgz db_dump.sql >> $BACKUP_DIR/backup-log.txt
κι εδώ;
Σε όλα αυτά τα σημεία χρειάζονται έξτρα έλεγχοι μετά από ΚΑΘΕ ΜΙΑ
εντολή ξεχωριστά, γιατί αν αποτύχει μία από αυτές, θα πάρει
σβάρνα όλο το υπόλοιπο script.
Όλα τα παραπάνω είναι, βέβαια, καθαρά προσωπική μου γνώμη και δεν
είσαι υποχρεωμένος να ακολουθήσεις το One True Keramidas
Shell-script Style(TM).
More information about the Linux-greek-users
mailing list