#!/usr/bin/python
import os
import os.path
import sys
import signal
from datetime import datetime
from subprocess import Popen, call, PIPE
_FORMAT='%Y%m%d-%H:%M:%S'
s='storage' # Source root
d='portable' # Destination container
c='macbookpro' # Destination name
r='%s/%s' % (d, c) # Destination root
t='/tmp/zfs_backupsblow' # FiFo path
send=None
recv=None
p=None
try:
for root in (s,d):
if call(['zfs','list','-H',root], stdout=PIPE):
print('ZFS %s not found' % root)
sys.exit()
if os.path.exists(t):
os.remove(t)
os.mkfifo(t)
p=open(t,'r+')
fss=Popen(['zfs','list','-rH','-t','filesystem','-o','name',s], stdout=PIPE).communicate()[0]
for fs in fss.strip().split('\n'):
dfs=fs.replace(s,r,1)
# Returns 0==success==false if found
full=call(['zfs','list','-H',dfs], stdout=PIPE)
date=datetime.now().strftime(_FORMAT)
print('Working on %s->%s@%s %s' % (fs, dfs, date, 'full' if full else 'incremental'))
call(['zfs','destroy','%s@previous' % fs], stderr=PIPE)
if call(['zfs','rename','%s@current' % fs,'%s@previous' % fs], stderr=PIPE) and not full:
print('Failed to rename previous current snapshot, falling back to full backup')
full=True
if call(['zfs','snapshot','%s@current' % fs]):
print('Failed to create current snapshot')
break
if full:
send=Popen(['zfs','send','%s@current' % fs], stdout=p)
else:
send=Popen(['zfs','send','-i','%s@previous' % fs,'%s@current' % fs], stdout=p)
recv=Popen(['zfs','recv','%s@%s' % (dfs, date)], stdin=p, stdout=PIPE, stderr=PIPE)
res=recv.communicate()
if recv.wait():
print('Failed to send|receive stdout:%s, stderr:%s' % (res))
break
finally:
if send and send.returncode is None:
os.kill(send.pid, signal.SIGKILL)
if recv and recv.returncode is None:
os.kill(recv.pid, signal.SIGKILL)
if p:
p.close()
os.remove(t)
"You give me Governor Ventura, myself and eight more of my fellow Navy SEALS -- and we could paralyze the entire country of the United States of America" --Richard Marcinko