backups: make the restore more defensive

Continue restore even if some fails failed to extract
This commit is contained in:
Marek Marczykowski-Górecki 2014-09-17 23:09:31 +02:00
parent 2c7fbd88e2
commit b506a0cc15
2 changed files with 50 additions and 20 deletions

View File

@ -889,7 +889,7 @@ class ExtractWorker(Process):
if self.tar2_process != None: if self.tar2_process != None:
if self.tar2_process.wait() != 0: if self.tar2_process.wait() != 0:
self.collect_tar_output() self.collect_tar_output()
raise QubesException( self.error_callback(
"ERROR: unable to extract files for {0}, tar " "ERROR: unable to extract files for {0}, tar "
"output:\n {1}".\ "output:\n {1}".\
format(self.tar2_current_file, format(self.tar2_current_file,
@ -914,6 +914,12 @@ class ExtractWorker(Process):
fcntl.fcntl(self.tar2_process.stderr.fileno(), fcntl.fcntl(self.tar2_process.stderr.fileno(),
fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.F_GETFL) | os.O_NONBLOCK)
self.tar2_stderr = [] self.tar2_stderr = []
elif not self.tar2_process:
# Extracting of the current archive failed, skip to the next
# archive
if not BACKUP_DEBUG:
os.remove(filename)
continue
else: else:
self.collect_tar_output() self.collect_tar_output()
if BACKUP_DEBUG: if BACKUP_DEBUG:
@ -975,7 +981,10 @@ class ExtractWorker(Process):
details = "\n".join(self.tar2_stderr) details = "\n".join(self.tar2_stderr)
else: else:
details = "%s failed" % run_error details = "%s failed" % run_error
raise QubesException("Error while processing '%s': %s " % \ self.tar2_process.terminate()
self.tar2_process.wait()
self.tar2_process = None
self.error_callback("Error while processing '%s': %s " % \
(self.tar2_current_file, details)) (self.tar2_current_file, details))
# Delete the file as we don't need it anymore # Delete the file as we don't need it anymore
@ -1747,6 +1756,7 @@ def backup_restore_do(restore_info,
vms_dirs.append(os.path.dirname(restore_info['dom0']['subdir'])) vms_dirs.append(os.path.dirname(restore_info['dom0']['subdir']))
vms_size += restore_info['dom0']['size'] vms_size += restore_info['dom0']['size']
try:
restore_vm_dirs (backup_location, restore_vm_dirs (backup_location,
restore_tmpdir, restore_tmpdir,
passphrase=passphrase, passphrase=passphrase,
@ -1762,6 +1772,13 @@ def backup_restore_do(restore_info,
encrypted=encrypted, encrypted=encrypted,
compressed=compressed, compressed=compressed,
appvm=appvm) appvm=appvm)
except QubesException as e:
if verify_only:
raise
else:
print_callback("Some errors occurred during data extraction, "
"continuing anyway to restore at least some "
"VMs")
else: else:
if verify_only: if verify_only:
print_callback("WARNING: Backup verification not supported for " print_callback("WARNING: Backup verification not supported for "

View File

@ -20,6 +20,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# #
# #
from multiprocessing import Event
from qubes.qubes import QubesVmCollection from qubes.qubes import QubesVmCollection
from qubes.qubes import QubesException from qubes.qubes import QubesException
@ -27,6 +28,7 @@ from qubes.backup import backup_restore_header
from qubes.backup import backup_restore_prepare from qubes.backup import backup_restore_prepare
from qubes.backup import backup_restore_print_summary from qubes.backup import backup_restore_print_summary
from qubes.backup import backup_restore_do from qubes.backup import backup_restore_do
import qubes.backup
import sys import sys
from optparse import OptionParser from optparse import OptionParser
@ -122,6 +124,11 @@ def main():
print >> sys.stderr, "Checking backup content..." print >> sys.stderr, "Checking backup content..."
error_detected = Event()
def error_callback(message):
error_detected.set()
print >> sys.stderr, message
restore_info = None restore_info = None
try: try:
restore_info = backup_restore_prepare( restore_info = backup_restore_prepare(
@ -131,7 +138,8 @@ def main():
host_collection=host_collection, host_collection=host_collection,
encrypted=options.decrypt, encrypted=options.decrypt,
compressed=options.compressed, compressed=options.compressed,
appvm=appvm) appvm=appvm,
error_callback=error_callback)
except QubesException as e: except QubesException as e:
print >> sys.stderr, "ERROR: %s" % str(e) print >> sys.stderr, "ERROR: %s" % str(e)
exit(1) exit(1)
@ -229,11 +237,16 @@ def main():
try: try:
backup_restore_do(restore_info, backup_restore_do(restore_info,
host_collection=host_collection) host_collection=host_collection,
error_callback=error_callback)
except QubesException as e: except QubesException as e:
print >> sys.stderr, "ERROR: %s" % str(e) print >> sys.stderr, "ERROR: %s" % str(e)
host_collection.unlock_db() host_collection.unlock_db()
if error_detected.is_set():
print "-> Completed with errors!"
exit(1)
else:
print "-> Done." print "-> Done."
main() main()