Bourne shell script for FreeBSD servers that use MySQL and the UFS2 filesystem.
Description:
1. Unmounts and deletes old snapshot if found.
2. The mysql(1) monitor is used to flush & lock the database
3. Using MySQL's SYSTEM(), to generate new snapshot using mksnap_ffs(8)
4. Mount resulting snapshot read-only to make it available for external backup.
It's meant to be used with cron(8) as a way to do make daily MySQL snapshots.
Also worth noting, other than the mysql monitor, it only depends on the
FreeBSD base system.
It has only been tested on FreeBSD. If you make changes to get it
working on other 4.4BSD systems that support UFS2, feel free to send any
enhancements.
Sample outputs:
# mysql_ufs_snapshot.sh -h
usage: mysql_ufs_snapshot [-h]
Description: Creates UFS2 snapshot of MySQL data directory
Then mounts the snapshot for further backup operations
Dependencies:
Deps: mksnap_ffs(8), mount(8), mdconfig(8), mysql(1), rm(1), awk(1)
# mysql_ufs_snapshot.sh
-> mysql_ufs_snapshot v2 starting
-> Old snapshot found
-> Detaching memory disk
-> Deleting old snapshot
-> Old snapshot deleted, continuing..
->
-> Launching mysql(1) monitor to lock tables and generate snapshot...
-> done
-> Attaching snapshot to memory disk
-> Snapshot mounted at /mnt/mysql_snapshot
#
#!/bin/sh # Copyright (c) 2007 TrueStep # Name: mysql_ufs_snapshot.sh # Author: Rory Arms - http://www.TrueStep.com/ # CDate: 2007-11-17 # Description: # 1. Unmounts and deletes old snapshot if found. # 2. The mysql(1) monitor is used to flush & lock the database # 3. Using MySQL's SYSTEM(), to generate new snapshot using mksnap_ffs(8) # 4. Mount resulting snapshot read-only to make it available for backup # # Installation: # 1. Make sure SNAP_MOUNT (see user knobs) directory exists. # 2. Put this file in a local path, /usr/local/sbin probably. # 3. Add a crontab(5) entry to execute this script as as often as desired. # Example crontab entry for daily execution at 2:30: # 30 2 * * * root /usr/local/sbin/mysql_ufs_snapshot.sh 1>/dev/null # # Tested with: FreeBSD 6.1, 6.2 # Deps: mksnap_ffs(8), mount(8), mdconfig(8), mysql(1), rm(1), awk(1) # $Id: mysql_ufs_snapshot.sh,v 1.1.1.1 2007/11/26 21:35:12 rorya Exp $ # user knobs SNAP_MOUNT="/mnt/mysql_snapshot" # where to mount read-only snapshot MYSQL_ROOT="/var/db/mysql" # mysql root directory, where the data lives MYSQL_PASSWORD="" # mysql password for the root user AUTHOR="TrueStep" NAME="mysql_ufs_snapshot" VERSION="2" SNAP_NAME="mysql_snap" # only change if you want a different snapshot filename PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin print() { echo "-> $*" } print_error() { echo "Error: $*" > /dev/stderr } print_stderr() { echo "$*" > /dev/stderr } banner() { print "$NAME v$VERSION starting" echo } prechecks() { # Check FreeBSD version if [ ! $(uname -r | awk -F. '{ print $1 }') -ge 5 ]; then print_error "FreeBSD 5 or higher required" exit 255 fi # Make sure MySQL is installed if [ ! -x $(which mysql) ]; then print_error "mysql(1) monitor not found" exit 255 fi # Make sure this is the root user if [ ! $(id -u) -eq 0 ]; then print_error "You are not a superuser" exit 255 fi # Make sure mount point exists if [ ! -e $SNAP_MOUNT ]; then print_error "mount point $SNAP_MOUNT does not exist, exiting" exit 255 fi # Resolve partition mount and snapshot location from MYSQL_ROOT SNAP_FS="/$(echo $MYSQL_ROOT | awk -F/ '{ print $2 }')" SNAP_DIR="/$(echo $MYSQL_ROOT | awk -F/ '{ print $2 }')/.snap" SNAP_PATH=${SNAP_DIR}/${SNAP_NAME} # Make sure the .snap directory exists in the target filesystem if [ ! -d $SNAP_DIR ]; then print_error "$SNAP_DIR doesn't exist, are you sure this is a UFS2 partition?" exit 255 fi } delete_oldsnap() { # Check to see if there is an existing snapshot from the last time # this was used if [ -e $SNAP_PATH ]; then print "Old snapshot found" # unmount the snapshot umount $SNAP_MOUNT # Detach memory disk print "Detaching memory disk" mdconfig -d -u 4 # Delete snapshot print "Deleting old snapshot" rm -f $SNAP_PATH # Check to make sure the memory disk detached successfully if [ ! $? = 0 ]; then print_error "memory disk did not detach, exiting" exit 255 fi print "Old snapshot deleted, continuing.. " print fi } create_snap() { # Check to see if there is a MySQL password if [ -z $MYSQL_PASSWORD ]; then MYSQL_OPTIONS="" else MYSQL_OPTIONS="-p$MYSQL_PASSWORD" fi # Flush mysql and use SYSTEM() to call mksnap_ffs(8) to create a # UFS2 snapshot # This is done because the MySQL read lock is only held while the # mysql(1) session is open. print "Launching mysql(1) monitor to lock tables and generate snapshot... " mysql $MYSQL_OPTIONS << SQL_MONITOR FLUSH TABLES WITH READ LOCK; SYSTEM mksnap_ffs /var '$SNAP_PATH'; UNLOCK TABLES; EXIT SQL_MONITOR print "done" # Check mysql(1) status code if [ ! $? = 0 ]; then print_error "mysql(1) failed to create snapshot, exiting" exit 255 fi } mount_snap() { # Attach snapshot file to a memory disk print "Attaching snapshot to memory disk" mdconfig -a -t vnode -o readonly -f $SNAP_PATH -u 4 # Check to make sure the snapshot attached if [ ! $? = 0 ]; then print_error "mdconfig(8) failed to attach snapshot $SNAP_PATH, exiting" exit 255 fi # Mount memory disk mount -r /dev/md4 $SNAP_MOUNT # Check to make sure the mount succeeded if [ ! $? = 0 ]; then print_error "mount(8) failed to mount snapshot, exiting" exit 255 fi print "Snapshot mounted at $SNAP_MOUNT" } print_usage() { print_stderr "usage: $NAME [-h]" print_stderr "Description: Creates UFS2 snapshot of MySQL data directory" print_stderr "Then mounts the snapshot for further backup operations" print_stderr "Dependencies:" print_stderr "Deps: mksnap_ffs(8), mount(8), mdconfig(8), mysql(1), rm(1), awk(1)" } print_version() { print_stderr "$NAME version $VERSION" } # main # print usage if -h is specified if [ ! -z $1 ]; then case $1 in -h|--help) print_usage ;; -v|-V|--version) print_version ;; esac exit 1 fi banner prechecks delete_oldsnap create_snap mount_snap
No comments:
Post a Comment