133 lines
4.6 KiB
Python
133 lines
4.6 KiB
Python
"""
|
|
(c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
|
|
Freezer general utils functions
|
|
"""
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
from freezer.engine import engine
|
|
from freezer.engine.tar import tar_builders
|
|
from freezer.utils import winutils
|
|
|
|
|
|
class TarBackupEngine(engine.BackupEngine):
|
|
DEFAULT_CHUNK_SIZE = 20000000
|
|
|
|
def __init__(
|
|
self, compression_algo, dereference_symlink, exclude, main_storage,
|
|
is_windows, encrypt_pass_file=None, dry_run=False,
|
|
chunk_size=DEFAULT_CHUNK_SIZE):
|
|
self.compression_algo = compression_algo
|
|
self.encrypt_pass_file = encrypt_pass_file
|
|
self.dereference_symlink = dereference_symlink
|
|
self.exclude = exclude
|
|
self._main_storage = main_storage
|
|
self.is_windows = is_windows
|
|
self.dry_run = dry_run
|
|
self.chunk_size = chunk_size
|
|
|
|
@property
|
|
def main_storage(self):
|
|
"""
|
|
:rtype: freezer.storage.storage.Storage
|
|
:return:
|
|
"""
|
|
return self._main_storage
|
|
|
|
def post_backup(self, backup, manifest):
|
|
self.main_storage.upload_meta_file(backup, manifest)
|
|
|
|
def backup_data(self, backup_path, manifest_path):
|
|
logging.info("Tar engine backup stream enter")
|
|
tar_command = tar_builders.TarCommandBuilder(
|
|
backup_path, self.compression_algo, self.is_windows)
|
|
if self.encrypt_pass_file:
|
|
tar_command.set_encryption(self.encrypt_pass_file)
|
|
if self.dereference_symlink:
|
|
tar_command.set_dereference(self.dereference_symlink)
|
|
tar_command.set_exclude(self.exclude)
|
|
tar_command.set_listed_incremental(manifest_path)
|
|
|
|
command = tar_command.build()
|
|
|
|
logging.info("Execution command: \n{}".format(command))
|
|
|
|
tar_process = subprocess.Popen(command, stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE, shell=True)
|
|
read_pipe = tar_process.stdout
|
|
tar_chunk = read_pipe.read(self.chunk_size)
|
|
while tar_chunk:
|
|
yield tar_chunk
|
|
tar_chunk = read_pipe.read(self.chunk_size)
|
|
tar_err = tar_process.communicate()[1]
|
|
if 'error' in tar_err.lower():
|
|
logging.exception('[*] Backup error: {0}'.format(tar_err))
|
|
sys.exit(1)
|
|
if tar_process.returncode:
|
|
logging.error('[*] Backup return code is not 0')
|
|
sys.exit(1)
|
|
logging.info("Tar engine streaming end")
|
|
|
|
@staticmethod
|
|
def check_process_output(process):
|
|
tar_err = process.communicate()[1]
|
|
|
|
if 'error' in tar_err.lower():
|
|
logging.exception('[*] Restore error: {0}'.format(tar_err))
|
|
sys.exit(1)
|
|
|
|
if process.returncode:
|
|
logging.error('[*] Restore return code is not 0')
|
|
sys.exit(1)
|
|
|
|
def restore_level(self, restore_path, read_pipe):
|
|
"""
|
|
Restore the provided file into backup_opt_dict.restore_abs_path
|
|
Decrypt the file if backup_opt_dict.encrypt_pass_file key is provided
|
|
"""
|
|
|
|
tar_command = tar_builders.TarCommandRestoreBuilder(
|
|
restore_path, self.compression_algo, self.is_windows)
|
|
|
|
if self.encrypt_pass_file:
|
|
tar_command.set_encryption(self.encrypt_pass_file)
|
|
|
|
if self.dry_run:
|
|
tar_command.set_dry_run()
|
|
|
|
command = tar_command.build()
|
|
|
|
if winutils.is_windows():
|
|
# on windows, chdir to restore path.
|
|
os.chdir(restore_path)
|
|
|
|
tar_process = subprocess.Popen(
|
|
command, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE, shell=True)
|
|
# Start loop reading the pipe and pass the data to the tar std input.
|
|
# If EOFError exception is raised, the loop end the std err will be
|
|
# checked for errors.
|
|
try:
|
|
while True:
|
|
tar_process.stdin.write(read_pipe.recv_bytes())
|
|
except EOFError:
|
|
logging.info('[*] Pipe closed as EOF reached. '
|
|
'Data transmitted successfully')
|
|
|
|
self.check_process_output(tar_process)
|