Skip to content

Instantly share code, notes, and snippets.

@aphyr
Created February 7, 2015 05:42
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aphyr/8a8ef46d4386a8a66793 to your computer and use it in GitHub Desktop.
Save aphyr/8a8ef46d4386a8a66793 to your computer and use it in GitHub Desktop.
Sync ZFS filesystems, incrementally if possible.
#!/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