Backups Blow - zfs_backupsblow.cron
#!/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
Google
 
© 2002-2010 Brandon Low 787 hits since April 13, 2009