Backup für einzelne Datenbanken

Bei diesem Projekt soll ein Skript erstellt werden, mit dessen Hilfe regelmäßig SQL-Dumps aus einer Datenbank extrahiert werden können, aber diese auch wieder (z.B. nach einem Server-Crash auf einem neuen System) in eine Datenbank geladen (importiert) werden können.

Dieses Skript wurde entwickelt um die Datenbanken auf (virtuellen) Root-Servern bei diversen Providern, die mit Plesk o.ä. administriert werden, zu sichern und gegebenenfalls wieder einspielen zu können. Dabei bedacht, dass die eigentliche Datenbank-Instanz mit dem entsprechenden User auch bei der Neuerstellung des Servers durch Plesk o.ä. zuvor eingerichtet wird. Dies dient der Funktionalität der Administrations-Oberfläche, die bei einem kompletten Import (inkl. der Benutzerrechte) unter gewissen Umständen nicht mehr gewährleistet ist.

Die meisten Web-Applikationen wie Joomla, WordPress usw. können damit recht schnell wieder auf einem neuen Server eingespielt und zum Laufen gebracht werden. Dabei reicht es zumeist die entsprechende Datenbank über die vom Provider zur Verfügung gestellte Administrations-Oberfläche (wie Plesk) zur erstellen, den Import mit dem Skript durchzuführen, die Dateien der Applikation in die Webroot zu legen und gegebenenfalls in dessen Konfiguration noch die Pfade anzupassen … das war's.

das Skript

Für die geforderte Aufgabe einzelne Datenbanken zu exportieren oder importieren wurde folgendes Skript erstellt:

dbsic.sh
#!/bin/bash
 
#########################
#
# DB-Backup-Script: Backup einzelner Datenbanken
#
# Skript zum Sichern und Importieren einzelner MySQL-Datenbanken.
#
# (c) M.K. Hitzigrath - http://hitzigrath.de
#
# last change: 25.07.2014
#
#########################
 
ownpath=$(dirname $0)
DBCSV=$ownpath/webdbs.csv
BUPATH=$ownpath/dbs
TMPpfx=/tmp
perms=0660
group=www-data
alter=31
 
function helpmesg {
  owncmd=$(basename $0)
  cat <<EOF
Skript fuer Backup der Datenbanken zu den einzelnen Websites.
 
Usages: $owncmd -s | -i [-b <Backup-Dir>] [-f <CSV-Datei>] [-r | -z] [-o "mysql/dump Optionen"] <webID>
        $owncmd -S [-b <Backup-Dir>] [-f <CSV-Datei>] [-r | -z] [-o "mysqldump Optionen"]
        $owncmd -h | -?    for help
 
Options:
 -s           Sichern der Datenbank
 -i           Import der Datenbank
 <webID>      ID (Kuerzel) der Website
 
 -S           Sichern aller Datenbanken in der CSV-Datei
 
 -b <string>  Angabe des Verzeichnis fuer die Backup-Dateien
              Default: $BUPATH
 -f <string>  Angabe der CSV-Datei mit den Daten fuer die DB-Instanzen
              Default: $DBCSV
 -r           SQL-Dump im RAW-Format
 -z           SQL-Dump als ZIP-Datei
 -o <string>  Optionen zu mysql (Import-Mode -i) bzw. mysqldump (Export-Mode -s)
              Dadurch werden die Optionen in der csv-Datei ueberschrieben.
 -B           Batch-Mode
 
Aufbau der CSV-Datei (mit Beispielen):
#DB-ID,DBname,DBuser,DBpwd,Export Options,Import Options
proddb,dbprod,dbadmin,pwsecret,--hex-blob --routines --events --skip-extended-insert
testdb,dbtest,testuser,secretpw,--log-error=testdberrors.log --complete-insert,--host=otherdbserver
kleinedb,dblittle,littleuser,littlepw
EOF
}
 
exlev=0
### Parameter settings
while getopts :b:f:o:rzisBh opt
do
  case $opt in
    b)
      BUPATH="$OPTARG"
      ;;
    f)
      DBCSV="$OPTARG"
      ;;
    o)
      opt_cmd="$OPTARG"
      ;;
    r)
      nocrypt="true"
      ;;
    z)
      nocrypt="true"
      opt_zip="true"
      ;;
    i)
      opt_imp="true"
      ;;
    s)
      opt_sic="true"
      ;;
    S)
      opt_all="true"
      opt_sic="true"
      ;;
    B)
      batchmode="true"
      ;;
    h|'?')
      [ ! -n "$batchmode" ] && helpmesg
      exit 1
      ;;
  esac
done
 
shift $((OPTIND - 1))
 
webIDs="$@"
if [ ! -n "$webIDs" ]
then
  if [ ! -n "$opt_all" ]
  then
    if [ ! -n "$batchmode" ]
    then
      echo "Kein webID benannt!"
      echo ""
      helpmesg
    fi
    exit 2
  fi
fi
 
if [ ! -n "$opt_sic" -a ! -n "$opt_imp" ]
then
  if [ ! -n "$batchmode" ]
  then
    echo "Fehlender Parameter! (-s -i)"
    echo ""
    helpmesg
  fi
  exit 3
fi
 
if [ -n "$opt_sic" -a -n "$opt_imp" ]
then
  if [ ! -n "$batchmode" ]
  then
    echo "Zuviele Parameter! (-s -i)"
    echo ""
    helpmesg
  fi
  exit 3
fi
 
if [ ! -f "$DBCSV" ]
then
  if [ ! -n "$batchmode" ]
  then
    echo "Keine Datei mit DB-Daten vorhanden! ($DBCSV)"
    echo ""
    helpmesg
  fi
  exit 4
fi
 
if [ ! -d "$BUPATH" ]
then
  mkdir $BUPATH
  if [ "$?" -ne "0" ]
  then
    if [ ! -n "$batchmode" ]
    then
      echo "Kann Verzeichnis fuer Backups nicht erstellen! ($BUPATH)"
      echo ""
      helpmesg
    fi
    exit 5
  fi
fi
 
if [ -n "$nocrypt" ]
then
  if [ -n "$opt_zip" ]
  then
    fext="sql.zip"
  else
    fext="sql"
  fi
else
  fext="sql.enc"
fi
 
exlev=0
 
[[ "$opt_all" ]] && webIDs="$(cat "$DBCSV" | grep -v "^#" | awk -F, '{ print $1 }')"
 
for webID in $webIDs
do
  csvline="$(cat "$DBCSV" | grep "^$webID,")"
  if [ ! "$csvline" = "" ]
  then
    dbname="$(awk -F, '{ print $2 }' <<<$csvline)"
    dbuser="$(awk -F, '{ print $3 }' <<<$csvline)"
    dbpwd="$(awk -F, '{ print $4 }' <<<$csvline)"
    if [[ "$opt_cmd" ]]
    then
      expopt="$opt_cmd"
    else
      expopt="$(awk -F, '{ print $5 }' <<<$csvline)"
    fi
    if [[ "$opt_cmd" ]]
    then
      impopt="$opt_cmd"
    else
      impopt="$(awk -F, '{ print $6 }' <<<$csvline)"
    fi
 
    tmpsql="$TMPpfx/dbsic-$webID-$$.sql"
    sbase="$BUPATH/$webID"
    dmpsql="$sbase.`date +%F`.$fext"
 
    if [ -n "$opt_sic" ]
    then
      if [ -e "$dmpsql" ]
      then
        sb1="${sbase}-1.$fext"
        if [ -e "$sb1" ]
        then
          sb2="${sbase}-2.$fext"
          if [ -e "$sb2" ]
          then
            sb3="${sbase}-3.$fext"
            if [ -e "$sb3" ]
            then
              rm -f $sb3
            fi
            mv -f $sb2 $sb3
          fi
          mv -f $sb1 $sb2
        fi
        mv -f $dmpsql $sb1
      fi
      [ ! -n "$batchmode" ] && echo "Erstelle SQL-Dump zu $webID"
      mysqldump --user=$dbuser --password=$dbpwd $expopt $dbname > $tmpsql
      if [ "$?" -ne "0" ]
      then
        [ ! -n "$batchmode" ] && echo "Fehler beim SQL-Dump! ($webID)"
        exlev=11
        [ -e "$tmpsql" ] && rm -f $tmpsql
      else
        if [ -n "$nocrypt" ]
        then
          if [ -n "$opt_zip" ]
          then
            cat $tmpsql | gzip > $dmpsql
            rm -f $tmpsql
          else
            mv -f $tmpsql $dmpsql
          fi
        else
          cat $tmpsql | gzip | openssl enc -a -out $dmpsql
          rm -f $tmpsql
        fi
        chmod $perms $dmpsql
        [[ "$group" ]] && chgrp $group $dmpsql
        find $BUPATH/ -type f -name "${webID}*" -mtime +$alter -exec rm -f {} >/dev/null 2>&1 \;
      fi
    elif [ -n "$opt_imp" ]
    then
      dmpsql=$(ls -rt1 ${sbase}* 2>/dev/null | tail -1)
      if [ -n "$dmpsql" ]
      then
        dumpext="${dmpsql##*.}"
        if [ "$dumpext" = "sql" -o "$dumpext" = "zip" ]
        then
          nocrypt="true"
          [ "$dumpext" = "zip" ] && opt_zip="true" || unset opt_zip
        else
          nocrypt=""
          unset nocrypt
        fi
 
        if [ ! -f "$dmpsql" ]
        then
          [ ! -n "$batchmode" ] && echo "Backup-Datei zu $webID ist keine Datei oder nicht vorhanden!"
        else
          [ ! -n "$batchmode" ] && echo "Datenbank-Import zu $webID."
          [ ! -n "$batchmode" ] && echo "Leere alte Datenbank."
          echo "DROP DATABASE IF EXISTS \`$dbname\`;" > $tmpsql
          echo "CREATE DATABASE \`$dbname\`;" >> $tmpsql
          mysql --user=$dbuser --password=$dbpwd $impopt < $tmpsql
          rm $tmpsql
          [ ! -n "$batchmode" ] && echo "Importiere SQL-Dump."
          if [ -n "$nocrypt" ]
          then
            if [ -n "$opt_zip" ]
            then
              zcat $dmpsql | mysql --user=$dbuser --password=$dbpwd --database=$dbname $impopt
            else
              mysql --user=$dbuser --password=$dbpwd --database=$dbname $impopt < $dmpsql
            fi
          else
            openssl enc -a -d -in $dmpsql | zcat | mysql --user=$dbuser --password=$dbpwd --database=$dbname $impopt
          fi
        fi
      fi
    fi
  else
    echo "Falsche webID! ($webID)"
    exlev=6
  fi
done
exit $exlev

die DB-Definitions-Datei

Um die einzelnen Datenbanken zu Dumpen (exportieren) wird eine Definition benötigt, die wie folgt aussieht:

webdbs.csv
#DB-ID,DBname,DBuser,DBpwd,Export Options,Import Options
proddb,dbprod,dbadmin,pwsecret,--hex-blob --routines --events --skip-extended-insert
testdb,dbtest,testuser,secretpw,--log-error=testdberrors.log --complete-insert,--host=otherdbserver
kleinedb,dblittle,littleuser,littlepw

Hierbei können die Optionen weggelassen werden wenn keine entsprechenden MySQL-Parameter benötigt werden.

FIXME

der Aufruf

Das Script erstellt zunächst ein Backup-Verzeichnis (wenn nicht schon vorhanden) und exportiert dann die angegebenen Datenbanken jeweils in eine SQL-Datei.

TODO