Created
February 7, 2015 05:42
-
-
Save aphyr/8a8ef46d4386a8a66793 to your computer and use it in GitHub Desktop.
Sync ZFS filesystems, incrementally if possible.
This file contains 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
#!/usr/bin/env ruby | |
# Synchronizes ZFS filesystems. | |
# | |
# Takes three args: source pool, destination pool, and filesystem name. | |
# | |
# Syncs most recent snapshot of filesystem from source to destination pool, | |
# using incremental transfer if possible. | |
# Take a snapshot line from zfs list -t snapshot and emit a struct | |
class Snapshot | |
attr_reader :pool | |
attr_reader :fs | |
attr_reader :snap | |
def initialize(str) | |
str =~ /\A(.+?)\/(.+?)@(.+?)\s+/ | |
@pool, @fs, @snap = $1, $2, $3 | |
end | |
# Map back into the same representation ZFS tools use | |
def to_s | |
"#{pool}/#{fs}@#{snap}" | |
end | |
end | |
# Parse args | |
src_pool, dest_pool, fs = ARGV | |
unless src_pool | |
puts "No source pool given." | |
exit 1 | |
end | |
unless dest_pool | |
puts "No destination pool given." | |
exit 1 | |
end | |
unless fs | |
puts "No filesystem given." | |
exit 1 | |
end | |
# All snapshots for the given filesystem | |
snapshots = `zfs list -t snapshot`.lines.map do |l| | |
Snapshot.new l | |
end.select do |s| | |
s.fs == fs | |
end | |
# Find most recent snapshots from both pools | |
last_src = snapshots.select { |s| s.pool == src_pool }.last | |
last_dest = snapshots.select { |s| s.pool == dest_pool }.last | |
unless last_src | |
puts "No snapshots for filesystem #{fs} on source pool #{src_pool}" | |
exit 2 | |
end | |
unless last_dest | |
puts "No snapshots for filesystem #{fs} on dest pool #{dest_pool}" | |
exit 2 | |
end | |
if last_src.snap == last_dest.snap | |
puts "Up to date! :D" | |
exit 0 | |
end | |
# Find corresponding snapshot in source pool | |
prev_src = snapshots.find do |s| | |
s.pool == src_pool and s.snap == last_dest.snap | |
end | |
if prev_src | |
# Incremental | |
puts "Incremental sync" | |
cmd = "zfs send -i '#{prev_src}' '#{last_src}' | zfs recv '#{dest_pool}/#{fs}'" | |
else | |
# Full | |
puts "Full sync" | |
cmd = "zfs send '#{last_src}' | zfs recv '#{dest_pool}/#{fs}'" | |
end | |
puts cmd | |
exec cmd |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment