freezer/freezer/engine/tar/tar_engine.py

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)