Created
January 31, 2013 12:52
-
-
Save matthiasg/4682641 to your computer and use it in GitHub Desktop.
zfs replication script from Ryan Kernan
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 | |
# | |
# Author: Ryan Kernan | |
# Date: September 23, 2011 | |
# Version: 1.1 | |
# Credits: Mike La Spina for the original concept and script http://blog.laspina.ca/ | |
# | |
# Mike La Spina - 1.1 added vars to support full paths on remote ssh executions | |
# Mike La Spina - 1.2 added var symbol to last_snap_shost input parse. | |
# | |
# Function: Provides snapshot and send process which replicates ZFS file systems from a source to target server. | |
# Maintains a runing snapshot archive for X days (X being the value of keep_snaps). | |
# | |
# The input format should conform to the following: | |
# source zfspath, source host, dest host | |
# | |
# eg. | |
# | |
# pool/zfsstore,host1,host2 | |
# | |
# Input parms:1 | |
# rep_list - a file name var of which the file contains a list of comma delimed zfs paths, source and target host names. | |
# keep_snaps - Number of days to keep snaps for. | |
# snap_list - temp file to list current snapshots. | |
# | |
# | |
# | |
ZFS=/usr/sbin/zfs | |
DATE=/usr/gnu/bin/date | |
SSH=/usr/bin/ssh | |
PFEXEC=/usr/bin/pfexec | |
export PATH=/usr/gnu/bin:/usr/bin:/usr/sbin:/sbin # Set Paths. | |
rep_list=$1 | |
keep_snaps=7 | |
snap_list=snaplist.lst | |
####################################################################################### | |
####################################Function########################################### | |
####################################################################################### | |
# | |
# Function parse the comma delimited input file and assign the field to the respective | |
# variables for file system, pool and host names. | |
# | |
# Global output parms | |
# zfspool | |
# zfspath | |
# shost | |
# dhost | |
parse_rep_list() { | |
rep_list_line=$1 | |
zfspool="$(echo $rep_list_line | cut -d/ -f1)" | |
zfspath="$(echo $rep_list_line | cut -d, -f1)" | |
shost="$(echo $rep_list_line | cut -d, -f2)" | |
dhost="$(echo $rep_list_line | cut -d, -f3)" | |
} | |
####################################################################################### | |
####################################Function########################################### | |
####################################################################################### | |
# | |
# Function issue zfs list commands and assign the variables the last snapshot names for | |
# both the source and destination hosts. | |
# | |
# Global input parms | |
# zfspath | |
# shost | |
# dhost | |
check_last_snap() { | |
last_snap_dhost="" | |
last_snap_shost="" | |
last_snap_shost=$( $PFEXEC $ZFS list -o name -t snapshot | grep $zfspath | tail -1 ) | |
last_snap_dhost=$( $SSH -n $dhost $PFEXEC $ZFS list -H -o name -r -t snapshot | grep $zfspath | tail -1 ) | |
true | |
} | |
####################################################################################### | |
####################################Function########################################### | |
####################################################################################### | |
# | |
# Function check if the destination $ZFS path exists and assign the result to the | |
# variable dhost_fs_name. | |
# | |
# Global input parms | |
# $zfspath | |
# dhost | |
dhost_fs_exists() { | |
dhost_fs_name="" | |
dhost_fs_name=$($SSH -n $dhost $PFEXEC $ZFS list -o name -H $zfspath | tail -1) | |
if [ "$dhost_fs_name" = "" ] | |
then | |
echo $($DATE) "->" $zfspath file system does not exist on target host $dhost. >> replicate.log | |
fi | |
} | |
####################################################################################### | |
####################################Function########################################### | |
####################################################################################### | |
# | |
# Function create a zfs path on the destination to allow the receive command | |
# funtionallity then issue zfs snap and send to transfer the zfs object to the | |
# destination host | |
# | |
# Global input parms | |
# zfspath | |
# dhost | |
dhost_create_fs() { | |
$SSH -n $dhost $PFEXEC $ZFS create -p $zfspath | |
$SSH -n $dhost $PFEXEC $ZFS set mountpoint=none $zfspath | |
last_snap_shost=$( $PFEXEC $ZFS list -o name -t snapshot -H | grep "${zfspath}\@" | tail -1 ) | |
echo $($DATE) "->" $last_snap_shost Initial replication start. >> replicate.log | |
$PFEXEC $ZFS send -v -R $last_snap_shost | $SSH $dhost $PFEXEC $ZFS recv -v -F -d $zfspool | |
echo $($DATE) "->" $last_snap_shost Initial replication end. >> replicate.log | |
} | |
####################################################################################### | |
####################################Function########################################### | |
####################################################################################### | |
# | |
# Function Issue a snapshot for the source zfs path | |
# | |
# Global input parms | |
# zfspath | |
create_fs_snap() { | |
snap_date="$($DATE +%m-%d-%y-%H:%M)" | |
echo $($DATE) "->" $zfspath@$snap_date Snapshot creation start. >> replicate.log | |
$PFEXEC $ZFS snapshot $zfspath@$snap_date | |
echo $($DATE) "->" $zfspath@$snap_date Snapshot creation end. >> replicate.log | |
} | |
####################################################################################### | |
####################################Function########################################### | |
####################################################################################### | |
# | |
# Function create a zfs send/recv command set based on a the zfs path source | |
# and target hosts for an established replication state. (aka incremental replication) | |
# | |
# Global input parms | |
# zfspath | |
# dhost | |
incr_repl_fs() { | |
echo $($DATE) "->" $last_snap_dhost $last_snap_shost Incremental send start. >> replicate.log | |
$PFEXEC $ZFS send -I $last_snap_dhost $last_snap_shost | $SSH $dhost $PFEXEC $ZFS recv -d -F $zfspool >> replicate.log | |
echo $($DATE) "->" $last_snap_dhost $last_snap_shost Incremental send end. >> replicate.log | |
} | |
####################################################################################### | |
####################################Function########################################### | |
####################################################################################### | |
# | |
# Function to clean up snapshots that are older than X days old X being the | |
# value set by "keep_snaps" on both the source and destination hosts. | |
clean_snaps() { | |
PreviousSnapDate="" | |
PreviousSnap="" | |
CurrentYear="$( $DATE +%y )" | |
CurrentMonth="$( $DATE +%m )" | |
CurrentDay="$( $DATE +%d )" | |
if [ "$zfspath" != "" ] | |
then | |
$PFEXEC $ZFS list -o name -t snapshot | grep “${zfspath}\@” > $snap_list | |
while read snaps | |
do | |
stringpos=0 | |
let stringpos=$(expr index "$snaps" @)+1 | |
SnapDate=$( $PFEXEC expr substr $snaps $stringpos 8 ) | |
let stringpos=$($PFEXEC expr index "$snaps" @)+10 | |
SnapTime=$( $PFEXEC expr substr $snaps $stringpos 5 ) | |
SnapDay="$(echo $SnapDate | cut -d- -f2)" | |
SnapMonth="$(echo $SnapDate | cut -d- -f1)" | |
SnapYear="$(echo $SnapDate | cut -d- -f3)" | |
SnapDate="$SnapMonth-$SnapDay-$SnapYear" | |
if [ "$($DATE +%m-%d-%y --date="$keep_snaps days ago")" = "$SnapDate" ] | |
then | |
echo "Destroying $SnapDate snapshot $snaps on $shost" >> replicate.log | |
$PFEXEC $ZFS destroy $snaps | |
echo "Destroying $SnapDate snapshot $snaps on $dhost" >> replicate.log | |
$PFEXEC $SSH -n $dhost $PFEXEC $ZFS destroy $snaps | |
fi | |
done < $snap_list | |
rm $snap_list | |
fi | |
} | |
####################################################################################### | |
#####################################Main Entery####################################### | |
####################################################################################### | |
# | |
# | |
# Init Global Parms | |
zfspath="" | |
shost="" | |
dhost="" | |
# Create the snapshots all at the same time | |
while read line | |
do | |
parse_rep_list $line | |
if [ "$zfspath" != "" ] | |
then | |
create_fs_snap >> replicate.log #Create a new snapshot of the path spec. | |
fi | |
done < $rep_list | |
# Send the snapshots to the remote and create the fs if required | |
while read line | |
do | |
parse_rep_list $line | |
if [ "$zfspath" != "" ] | |
then | |
dhost_fs_exists # Test for the existence of our listed | |
# zfs file system path on the target host. | |
if [ "$dhost_fs_name" ] | |
then | |
check_last_snap >> replicate.log # Get the start and stop snaps. | |
incr_repl_fs >> replicate.log # Initiate a dif replication. | |
clean_snaps # Clean up any snapshots that are X days old. | |
else | |
dhost_create_fs >> replicate.log # Create a first time replication. | |
fi | |
fi | |
done < $rep_list | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment