backup: multiple fixes for the backup process, including non-encrypted backups
- Ensure backup without encryption is working - Implemented progress feedback through a global variable - Ask user for a passphrase used for encryption or for verification
This commit is contained in:
parent
23065f6fa0
commit
361741b8aa
@ -1049,6 +1049,8 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
# If not APPVM, STDOUT is a local file
|
# If not APPVM, STDOUT is a local file
|
||||||
backup_stdout = open(backup_target,'wb')
|
backup_stdout = open(backup_target,'wb')
|
||||||
|
|
||||||
|
passphrase = raw_input("Please enter the pass phrase that will be used to encrypt/verify the backup:\n")
|
||||||
|
passphrase = passphrase.replace("\r","").replace("\n","")
|
||||||
|
|
||||||
blocks_backedup = 0
|
blocks_backedup = 0
|
||||||
progress = blocks_backedup * 11 / total_backup_sz
|
progress = blocks_backedup * 11 / total_backup_sz
|
||||||
@ -1088,7 +1090,8 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
break
|
break
|
||||||
|
|
||||||
print "Sending file",filename
|
print "Sending file",filename
|
||||||
tar_final_cmd = ["tar", "-cO", "-C", self.base_dir, filename]
|
# This tar used for sending data out need to be as simple, as simple, as featureless as possible. It will not be verified before untaring.
|
||||||
|
tar_final_cmd = ["tar", "-cO", "--posix", "-C", self.base_dir, filename]
|
||||||
final_proc = subprocess.Popen (tar_final_cmd, stdin=subprocess.PIPE, stdout=self.backup_stdout)
|
final_proc = subprocess.Popen (tar_final_cmd, stdin=subprocess.PIPE, stdout=self.backup_stdout)
|
||||||
final_proc.wait()
|
final_proc.wait()
|
||||||
|
|
||||||
@ -1098,6 +1101,14 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
|
|
||||||
print "Finished sending thread"
|
print "Finished sending thread"
|
||||||
|
|
||||||
|
global blocks_backedup
|
||||||
|
blocks_backedup = 0
|
||||||
|
def compute_progress(new_size, total_backup_sz):
|
||||||
|
global blocks_backedup
|
||||||
|
blocks_backedup += new_size
|
||||||
|
progress = blocks_backedup / float(total_backup_sz)
|
||||||
|
progress_callback(round(progress*100,2))
|
||||||
|
|
||||||
to_send = Queue()
|
to_send = Queue()
|
||||||
send_proc = Send_Worker(to_send, backup_tmpdir, backup_stdout)
|
send_proc = Send_Worker(to_send, backup_tmpdir, backup_stdout)
|
||||||
send_proc.start()
|
send_proc.start()
|
||||||
@ -1113,6 +1124,7 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
if not os.path.isdir(os.path.dirname(backup_tempfile)):
|
if not os.path.isdir(os.path.dirname(backup_tempfile)):
|
||||||
os.makedirs(os.path.dirname(backup_tempfile))
|
os.makedirs(os.path.dirname(backup_tempfile))
|
||||||
|
|
||||||
|
# The first tar cmd can use any complex feature as we want. Files will be verified before untaring this.
|
||||||
tar_cmdline = ["tar", "-Pc", "-f", backup_pipe,'--sparse','--tape-length',str(1000000),'-C',qubes_base_dir,
|
tar_cmdline = ["tar", "-Pc", "-f", backup_pipe,'--sparse','--tape-length',str(1000000),'-C',qubes_base_dir,
|
||||||
filename["path"].split(os.path.normpath(qubes_base_dir)+"/")[1]
|
filename["path"].split(os.path.normpath(qubes_base_dir)+"/")[1]
|
||||||
]
|
]
|
||||||
@ -1130,19 +1142,25 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
running = []
|
running = []
|
||||||
while run_error == "paused":
|
while run_error == "paused":
|
||||||
|
|
||||||
# Start encrypt
|
|
||||||
pipe = open(backup_pipe,'rb')
|
pipe = open(backup_pipe,'rb')
|
||||||
# If no cipher is provided, the data is forwarded unencrypted !!!
|
|
||||||
encryptor = subprocess.Popen (["openssl", "enc", "-e", "-aes-256-cbc", "-pass", "pass:azerty"], stdin=pipe, stdout=subprocess.PIPE)
|
|
||||||
|
|
||||||
# Start HMAC
|
# Start HMAC
|
||||||
hmac = subprocess.Popen (["openssl", "dgst", "-hmac", "azerty"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
hmac = subprocess.Popen (["openssl", "dgst", "-hmac", passphrase], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||||
|
|
||||||
# Prepare a first chunk
|
# Prepare a first chunk
|
||||||
chunkfile = backup_tempfile + "." + "%03d" % i
|
chunkfile = backup_tempfile + "." + "%03d" % i
|
||||||
i += 1
|
i += 1
|
||||||
chunkfile_p = open(chunkfile,'wb')
|
chunkfile_p = open(chunkfile,'wb')
|
||||||
run_error = wait_backup_feedback(progress_callback, encryptor, chunkfile_p, total_backup_sz, hmac=hmac, vmproc=vmproc, addproc=tar_sparse)
|
|
||||||
|
if encrypt:
|
||||||
|
# Start encrypt
|
||||||
|
# If no cipher is provided, the data is forwarded unencrypted !!!
|
||||||
|
# Also note that the
|
||||||
|
encryptor = subprocess.Popen (["openssl", "enc", "-e", "-aes-256-cbc", "-pass", "pass:"+passphrase], stdin=pipe, stdout=subprocess.PIPE)
|
||||||
|
run_error = wait_backup_feedback(compute_progress, encryptor.stdout, encryptor, chunkfile_p, total_backup_sz, hmac=hmac, vmproc=vmproc, addproc=tar_sparse)
|
||||||
|
else:
|
||||||
|
run_error = wait_backup_feedback(compute_progress, pipe, None, chunkfile_p, total_backup_sz, hmac=hmac, vmproc=vmproc, addproc=tar_sparse)
|
||||||
|
|
||||||
chunkfile_p.close()
|
chunkfile_p.close()
|
||||||
|
|
||||||
print "Wait_backup_feedback returned:",run_error
|
print "Wait_backup_feedback returned:",run_error
|
||||||
@ -1152,9 +1170,6 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
|
|
||||||
# Send the chunk to the backup target
|
# Send the chunk to the backup target
|
||||||
to_send.put(chunkfile.split(os.path.normpath(backup_tmpdir)+"/")[1])
|
to_send.put(chunkfile.split(os.path.normpath(backup_tmpdir)+"/")[1])
|
||||||
#tar_final_cmd = ["tar", "-cO", "-C", backup_tmpdir, chunkfile.split(os.path.normpath(backup_tmpdir)+"/")[1]]
|
|
||||||
#final_proc = subprocess.Popen (tar_final_cmd, stdin=subprocess.PIPE, stdout=backup_stdout)
|
|
||||||
#final_proc.wait()
|
|
||||||
|
|
||||||
# Close HMAC
|
# Close HMAC
|
||||||
hmac.stdin.close()
|
hmac.stdin.close()
|
||||||
@ -1171,10 +1186,7 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
|
|
||||||
# Send the HMAC to the backup target
|
# Send the HMAC to the backup target
|
||||||
to_send.put(chunkfile.split(os.path.normpath(backup_tmpdir)+"/")[1]+".hmac")
|
to_send.put(chunkfile.split(os.path.normpath(backup_tmpdir)+"/")[1]+".hmac")
|
||||||
#tar_final_cmd = ["tar", "-cO", "-C", backup_tmpdir, chunkfile.split(os.path.normpath(backup_tmpdir)+"/")[1]+".hmac"]
|
|
||||||
#final_proc = subprocess.Popen (tar_final_cmd, stdin=subprocess.PIPE, stdout=backup_stdout)
|
|
||||||
#final_proc.wait()
|
|
||||||
|
|
||||||
if tar_sparse.poll() == None:
|
if tar_sparse.poll() == None:
|
||||||
# Release the next chunk
|
# Release the next chunk
|
||||||
print "Release next chunk for process:",tar_sparse.poll()
|
print "Release next chunk for process:",tar_sparse.poll()
|
||||||
@ -1184,7 +1196,8 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
else:
|
else:
|
||||||
print "Finished tar sparse with error",tar_sparse.poll()
|
print "Finished tar sparse with error",tar_sparse.poll()
|
||||||
|
|
||||||
|
pipe.close()
|
||||||
|
|
||||||
# Close the backup target and wait for it to finish
|
# Close the backup target and wait for it to finish
|
||||||
#backup_stdout.close()
|
#backup_stdout.close()
|
||||||
|
|
||||||
@ -1206,7 +1219,7 @@ def backup_do_copy(base_backup_dir, files_to_backup, progress_callback = None, e
|
|||||||
' - all of the monitored processes except vmproc finished successfully (vmproc termination is controlled by the python script)
|
' - all of the monitored processes except vmproc finished successfully (vmproc termination is controlled by the python script)
|
||||||
' - streamproc does not delivers any data anymore (return with the error "paused")
|
' - streamproc does not delivers any data anymore (return with the error "paused")
|
||||||
'''
|
'''
|
||||||
def wait_backup_feedback(progress_callback, streamproc, backup_target, total_backup_sz, hmac=None, vmproc=None, addproc=None, remove_trailing_bytes=0):
|
def wait_backup_feedback(progress_callback, in_stream, streamproc, backup_target, total_backup_sz, hmac=None, vmproc=None, addproc=None, remove_trailing_bytes=0):
|
||||||
|
|
||||||
buffer_size = 4096
|
buffer_size = 4096
|
||||||
|
|
||||||
@ -1215,12 +1228,9 @@ def wait_backup_feedback(progress_callback, streamproc, backup_target, total_bac
|
|||||||
blocks_backedup = 0
|
blocks_backedup = 0
|
||||||
while run_count > 0 and run_error == None:
|
while run_count > 0 and run_error == None:
|
||||||
|
|
||||||
buffer = streamproc.stdout.read(buffer_size)
|
buffer = in_stream.read(buffer_size)
|
||||||
|
|
||||||
blocks_backedup += len(buffer)
|
progress_callback(len(buffer),total_backup_sz)
|
||||||
|
|
||||||
progress = blocks_backedup / float(total_backup_sz)
|
|
||||||
progress_callback(round(progress*100,2))
|
|
||||||
|
|
||||||
run_count = 0
|
run_count = 0
|
||||||
if hmac:
|
if hmac:
|
||||||
@ -1240,37 +1250,6 @@ def wait_backup_feedback(progress_callback, streamproc, backup_target, total_bac
|
|||||||
else:
|
else:
|
||||||
run_count += 1
|
run_count += 1
|
||||||
|
|
||||||
retcode=streamproc.poll()
|
|
||||||
if retcode != None:
|
|
||||||
if retcode != 0:
|
|
||||||
run_error = "streamproc"
|
|
||||||
print "INFO: run error"
|
|
||||||
elif retcode == 0 and len(buffer) <= 0:
|
|
||||||
print "INFO: no data"
|
|
||||||
return ""
|
|
||||||
else:
|
|
||||||
print "INFO: last packet"
|
|
||||||
#if remove_trailing_bytes > 0:
|
|
||||||
# print buffer.encode("hex")
|
|
||||||
# buffer = buffer[:-remove_trailing_bytes]
|
|
||||||
# print buffer.encode("hex")
|
|
||||||
|
|
||||||
backup_target.write(buffer)
|
|
||||||
|
|
||||||
if hmac:
|
|
||||||
hmac.stdin.write(buffer)
|
|
||||||
|
|
||||||
run_count += 1
|
|
||||||
else:
|
|
||||||
#print "Process running:",len(buffer)
|
|
||||||
# Process still running
|
|
||||||
backup_target.write(buffer)
|
|
||||||
|
|
||||||
if hmac:
|
|
||||||
hmac.stdin.write(buffer)
|
|
||||||
|
|
||||||
run_count += 1
|
|
||||||
|
|
||||||
if vmproc:
|
if vmproc:
|
||||||
retcode = vmproc.poll()
|
retcode = vmproc.poll()
|
||||||
if retcode != None:
|
if retcode != None:
|
||||||
@ -1281,6 +1260,47 @@ def wait_backup_feedback(progress_callback, streamproc, backup_target, total_bac
|
|||||||
# VM should run until the end
|
# VM should run until the end
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
if streamproc:
|
||||||
|
retcode=streamproc.poll()
|
||||||
|
if retcode != None:
|
||||||
|
if retcode != 0:
|
||||||
|
run_error = "streamproc"
|
||||||
|
elif retcode == 0 and len(buffer) <= 0:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
#print "INFO: last packet"
|
||||||
|
#if remove_trailing_bytes > 0:
|
||||||
|
# print buffer.encode("hex")
|
||||||
|
# buffer = buffer[:-remove_trailing_bytes]
|
||||||
|
# print buffer.encode("hex")
|
||||||
|
|
||||||
|
backup_target.write(buffer)
|
||||||
|
|
||||||
|
if hmac:
|
||||||
|
hmac.stdin.write(buffer)
|
||||||
|
|
||||||
|
run_count += 1
|
||||||
|
else:
|
||||||
|
#print "Process running:",len(buffer)
|
||||||
|
# Process still running
|
||||||
|
backup_target.write(buffer)
|
||||||
|
|
||||||
|
if hmac:
|
||||||
|
hmac.stdin.write(buffer)
|
||||||
|
|
||||||
|
run_count += 1
|
||||||
|
|
||||||
|
else:
|
||||||
|
if len(buffer) <= 0:
|
||||||
|
return ""
|
||||||
|
else:
|
||||||
|
backup_target.write(buffer)
|
||||||
|
|
||||||
|
if hmac:
|
||||||
|
hmac.stdin.write(buffer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return run_error
|
return run_error
|
||||||
|
|
||||||
def restore_vm_dir (backup_dir, src_dir, dst_dir, vm_spec, print_callback=None, error_callback=None, encrypted=False, appvm=None):
|
def restore_vm_dir (backup_dir, src_dir, dst_dir, vm_spec, print_callback=None, error_callback=None, encrypted=False, appvm=None):
|
||||||
|
Loading…
Reference in New Issue
Block a user