backup-manager: add ability to start archives
This will allow things to run completely on autopilot, creating archives on S3 when necessary.
This commit is contained in:
parent
b5533a843f
commit
abbbbba970
1 changed files with 37 additions and 0 deletions
|
@ -3,6 +3,8 @@
|
||||||
# Script to manage S3-stored backups
|
# Script to manage S3-stored backups
|
||||||
|
|
||||||
import optparse
|
import optparse
|
||||||
|
import os
|
||||||
|
import pwd
|
||||||
import secrets
|
import secrets
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
@ -11,6 +13,8 @@ from boto.s3.connection import S3Connection
|
||||||
from boto.s3.key import Key
|
from boto.s3.key import Key
|
||||||
import boto.exception
|
import boto.exception
|
||||||
|
|
||||||
|
from subprocess import *
|
||||||
|
|
||||||
def open_s3(accesskey, sharedkey):
|
def open_s3(accesskey, sharedkey):
|
||||||
return S3Connection(accesskey, sharedkey)
|
return S3Connection(accesskey, sharedkey)
|
||||||
|
|
||||||
|
@ -148,6 +152,23 @@ def make_restore_script(backup, expire=86400):
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
def start_archive(hosts):
|
||||||
|
"Starts an archive operation for a list of hosts."
|
||||||
|
if 'LOGNAME' in os.environ:
|
||||||
|
username = os.environ['LOGNAME']
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
username = pwd.getpwuid(os.getuid()).pw_name
|
||||||
|
except KeyError:
|
||||||
|
username = 'nobody'
|
||||||
|
|
||||||
|
cmd = ['/usr/share/backuppc/bin/BackupPC_archiveStart', 'archives3',
|
||||||
|
username]
|
||||||
|
cmd.extend(hosts)
|
||||||
|
|
||||||
|
proc = Popen(cmd)
|
||||||
|
proc.communicate()
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# check command line options
|
# check command line options
|
||||||
parser = optparse.OptionParser(
|
parser = optparse.OptionParser(
|
||||||
|
@ -175,6 +196,8 @@ def main():
|
||||||
help="Test mode; don't actually delete")
|
help="Test mode; don't actually delete")
|
||||||
parser.add_option("-u", "--unfinalized", dest="unfinalized",
|
parser.add_option("-u", "--unfinalized", dest="unfinalized",
|
||||||
action="store_true", help="Consider unfinalized backups")
|
action="store_true", help="Consider unfinalized backups")
|
||||||
|
parser.add_option("-s", "--start-backups", dest="start",
|
||||||
|
action="store_true", help="When used with --age, start backups for hosts with fewer than keep+1 backups")
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
@ -195,6 +218,9 @@ def main():
|
||||||
if args[0] != 'delete' and options.age:
|
if args[0] != 'delete' and options.age:
|
||||||
parser.error('--age only makes sense with delete')
|
parser.error('--age only makes sense with delete')
|
||||||
|
|
||||||
|
if options.start and not (args[0] == 'delete' and options.age):
|
||||||
|
parser.error('--start-backups only makes sense with delete and --age')
|
||||||
|
|
||||||
if args[0] != 'script' and (options.expire or options.filename):
|
if args[0] != 'script' and (options.expire or options.filename):
|
||||||
parser.error('--expire and --filename only make sense with script')
|
parser.error('--expire and --filename only make sense with script')
|
||||||
|
|
||||||
|
@ -271,11 +297,13 @@ def main():
|
||||||
elif args[0] == 'delete':
|
elif args[0] == 'delete':
|
||||||
if options.age:
|
if options.age:
|
||||||
maxage = int(options.age)*86400
|
maxage = int(options.age)*86400
|
||||||
|
needs_backup = []
|
||||||
for bucket in buckets:
|
for bucket in buckets:
|
||||||
hostnames = list_backups(bucket)
|
hostnames = list_backups(bucket)
|
||||||
for hostname in hostnames.keys():
|
for hostname in hostnames.keys():
|
||||||
backups = hostnames[hostname]
|
backups = hostnames[hostname]
|
||||||
backuplist = sorted(backups.keys())
|
backuplist = sorted(backups.keys())
|
||||||
|
oldest_timestamp = -1
|
||||||
# remove a number of recent backups from the delete list
|
# remove a number of recent backups from the delete list
|
||||||
to_ignore = int(options.keep)
|
to_ignore = int(options.keep)
|
||||||
while to_ignore > 0:
|
while to_ignore > 0:
|
||||||
|
@ -289,9 +317,12 @@ def main():
|
||||||
sys.stdout.write('Ignoring in-progress backup %s #%i\n' % (hostname, backupnum))
|
sys.stdout.write('Ignoring in-progress backup %s #%i\n' % (hostname, backupnum))
|
||||||
else:
|
else:
|
||||||
sys.stdout.write('Keeping recent backup %s #%i (%i files, age %.2f days)\n' % (hostname, backupnum, filecount, delta/86400.0))
|
sys.stdout.write('Keeping recent backup %s #%i (%i files, age %.2f days)\n' % (hostname, backupnum, filecount, delta/86400.0))
|
||||||
|
if timestamp < oldest_timestamp:
|
||||||
|
oldest_timestamp = timestamp
|
||||||
to_ignore -= 1
|
to_ignore -= 1
|
||||||
else:
|
else:
|
||||||
to_ignore = 0
|
to_ignore = 0
|
||||||
|
deletes = 0
|
||||||
for backupnum in backuplist:
|
for backupnum in backuplist:
|
||||||
filecount = len(backups[backupnum]['keys'])
|
filecount = len(backups[backupnum]['keys'])
|
||||||
if backups[backupnum]['finalized'] > 0:
|
if backups[backupnum]['finalized'] > 0:
|
||||||
|
@ -318,6 +349,12 @@ def main():
|
||||||
backups[backupnum]['finalkey'].delete()
|
backups[backupnum]['finalkey'].delete()
|
||||||
sys.stdout.write('!')
|
sys.stdout.write('!')
|
||||||
sys.stdout.write('\n')
|
sys.stdout.write('\n')
|
||||||
|
deletes += 1
|
||||||
|
if (len(backuplist)-deletes) < int(options.keep):
|
||||||
|
needs_backup.append((oldest_timestamp, hostname))
|
||||||
|
if options.start and len(needs_backup) > 0:
|
||||||
|
sys.stdout.write('Starting archive operations for hosts: %s\n' % ', '.join(x[1] for x in sorted(needs_backup)))
|
||||||
|
start_archive([x[1] for x in sorted(needs_backup)])
|
||||||
elif options.host and options.backupnum:
|
elif options.host and options.backupnum:
|
||||||
for bucket in buckets:
|
for bucket in buckets:
|
||||||
hostnames = list_backups(bucket)
|
hostnames = list_backups(bucket)
|
||||||
|
|
Loading…
Reference in a new issue