#!/bin/zsh -f

umask 0077

# user definable parameters
# days: for how many days should backups be kept
days=30
targetlvol=/dev/vol01/mysql
backupdir=/backup/mysql
# Important!
#   The mysql user (that is supplied by the username and password parameters)
#   must have the RELOAD privilege to be able to issue a global lock on all
#   tables (via a "FLUSH TABLES WITH READ LOCK").
mysql_username=backup_user
mysql_password=password
backup_basename=myserver__mysql
tmplvolname=backup_snapshot_lvol
storedir=${backupdir}/store
logfile=${backupdir}/backup.log
datecmd=(date --rfc-2822)

touch "${logfile}" 2> /dev/null
[[ ! -w "${logfile}" ]] && {echo "Error (${0:t}): cannot write to logfile (${logfile})!"; exit 1}

echo "**********************************
Starting backup at: `${datecmd[@]}`" >> "${logfile}"

[[ ! -d "${backupdir}" || ! -r "${backupdir}" || ! -x "${backupdir}" || ! -w "${backupdir}" ]] && {echo "Backup directory (${backupdir}) does not exist or is not readable+writeable+searchable by current process. Backup failed." >> "${logfile}"; exit 1}

if [[ -z "${backup_basename}" ]]; then
  backup_basename=$(hostname --long)
fi

echo "
`${datecmd[@]}`
Parameters:
  mysql username=${mysql_username}
  mysql password=${(l:${#mysql_password}::*:)}
  targetlvol=${targetlvol}
  backup basename=${backup_basename}" >> "${logfile}"

[[ -z "${mysql_username}" || -z "${mysql_password}" || -z "${targetlvol}" || -z "${backup_basename}" ]] && {echo "Not enough parameters!" >> "${logfile}" } && return

backupfile=${backupdir}/${backup_basename}__$(date +%Y-%m-%d)
if [[ -f "${backupfile}.tar.bz2" ]]; then
  rm -f "${backupfile}.tar.bz2" 2>> "${logfile}" || {echo "Backup file already exists and could not be deleted. Backup of target failed." >> "${logfile}"; return}
fi

echo "Locking database ..." >> "${logfile}"
mysql --user="${mysql_username}" --password="${mysql_password}" >> "${logfile}" 2>&1 <<EOF1
flush tables with read lock;
flush logs;
EOF1
db_locked=1
if lvdisplay "${targetlvol}" > /dev/null 2>&1; then
  echo "Creating LVM snapshot ..." >> "${logfile}"
  if lvcreate --snapshot --size=500M --name="${tmplvolname}" "${targetlvol}" >> "${logfile}" 2>&1; then
    echo "Unlocking database ..." >> "${logfile}"
    mysql --user="${mysql_username}" --password="${mysql_password}" >> "${logfile}" 2>&1 <<EOF2
unlock tables;
EOF2
    db_locked=0
    mntdir=/tmp/backup${RANDOM}
    spath=$(dirname "${targetlvol}")/${tmplvolname}
    if mkdir "${mntdir}" >> "${logfile}" 2>&1; then
      if mount "${spath}" "${mntdir}" >> "${logfile}" 2>&1; then
        echo "Creating archive ..." >> "${logfile}"
        cd "${mntdir}" >> "${logfile}" 2>&1
        nice -n +19 tar cjf "${backupfile}.tar.bz2" ./* >> "${logfile}" 2>&1
        cd /
        umount "${mntdir}" >> "${logfile}" 2>&1
      else
        echo "Failed to mount the snapshot." >> "${logfile}"
      fi
      rmdir "${mntdir}" >> "${logfile}" 2>&1
    else
      echo "Failed to create mount point directory." >> "${logfile}"
    fi
    echo "Removing snapshot ..." >> "${logfile}"
    lvremove -f "${spath}" >> "${logfile}" 2>&1
  else
    echo "Failed to create snapshot of ${targetlvol}." >> "${logfile}"
  fi
else
  echo "No LVM logical volume was found at ${targetlvol}." >> "${logfile}"
fi
if [[ ${db_locked} -gt 0 ]]; then
  mysql --user="${mysql_username}" --password="${mysql_password}" >> "${logfile}" 2>&1 <<EOF3
unlock tables;
EOF3
fi
[[ ! -f "${backupfile}.tar.bz2" ]] && {echo "Failed to create backup." >> "${logfile}"; return}
if [[ "$(date +%d)" == "01" && -d "${storedir}" && -f "${backupfile}.tar.bz2" ]]; then
  echo "Today is the first day of the month. Making a copy of the backup in ${storedir} ..." >> "${logfile}"
  cp "${backupfile}.tar.bz2" "${storedir}" >> "${logfile}" 2>&1
fi

echo "
Cleaning up old backups ..." >> "${logfile}"
[[ -d "${backupdir}"  && ${days} -gt 0 ]] && find "${backupdir}" -xdev -maxdepth 1 -type f -name '*.tar.bz2' -ctime +${days} -exec rm -f {} ";" -printf "%f was deleted.\n" >> "${logfile}" 2>&1
echo "
End of backup at: $(${datecmd[@]})
" >> "${logfile}"

