diff --git a/autoxtrabackup.py b/autoxtrabackup.py index ce3d627f..f412cf0c 100644 --- a/autoxtrabackup.py +++ b/autoxtrabackup.py @@ -127,6 +127,8 @@ def validate_file(file): default='/etc/bck.conf', show_default=True, help="Read options from the given file") +@click.option('--tag', + help="Pass the tag string for each backup") @click.option('-v', '--verbose', is_flag=True, help="Be verbose (print to console)") @click.option('-lf', @@ -156,7 +158,7 @@ def validate_file(file): is_eager=False, help="Print help message and exit.") @click.pass_context -def all_procedure(ctx, prepare, backup, partial, verbose, log_file, log, defaults_file, dry_run, test_mode): +def all_procedure(ctx, prepare, backup, partial, tag, verbose, log_file, log, defaults_file, dry_run, test_mode): logger.setLevel(log) formatter = logging.Formatter(fmt='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S') @@ -216,12 +218,20 @@ def all_procedure(ctx, prepare, backup, partial, verbose, log_file, log, default # print("Prepare") elif backup and not test_mode: if not dry_run: - b = Backup(config=defaults_file) - b.all_backup() + if tag: + b = Backup(config=defaults_file, tag=tag) + b.all_backup() + else: + b = Backup(config=defaults_file) + b.all_backup() else: logger.warning("Dry run enabled!") - b = Backup(config=defaults_file, dry_run=1) - b.all_backup() + if tag: + b = Backup(config=defaults_file, dry_run=1, tag=tag) + b.all_backup() + else: + b = Backup(config=defaults_file, dry_run=1) + b.all_backup() # print("Backup") elif partial: if not dry_run: diff --git a/master_backup_script/backuper.py b/master_backup_script/backuper.py index 8e13d21c..c3ba2565 100755 --- a/master_backup_script/backuper.py +++ b/master_backup_script/backuper.py @@ -24,12 +24,29 @@ class Backup(GeneralClass): - def __init__(self, config='/etc/bck.conf', dry_run=0): + def __init__(self, config='/etc/bck.conf', dry_run=0, tag=None): self.conf = config self.dry = dry_run + self.tag = tag # Call GeneralClass for storing configuration options super().__init__(self.conf) + @staticmethod + def add_tag(backup_dir, backup_name, type, tag_string, backup_status): + ''' + Static method for adding backup tags + :param backup_dir: The backup dir path + :param backup_name: The backup name(timestamped) + :param type: The backup type - Full/Inc + :param tag_string: The passed tag string + :param backup_status: Status: OK or Status: Failed + :return: True if no exception + ''' + with open('{}/backup_tags.txt'.format(backup_dir), 'a') as bcktags: + bcktags.write("{0}\t{1}\t{2}\t'{3}'\n".format(backup_name, type, backup_status, tag_string)) + + return True + @staticmethod def sorted_ls(path): ''' @@ -125,8 +142,7 @@ def mysql_connection_flush_logs(self): self.mycnf, self.mysql_user, self.mysql_password, - self.mysql_socket - ) + self.mysql_socket) else: command_connection += ' --port={}' command_connection += command_execute @@ -136,8 +152,7 @@ def mysql_connection_flush_logs(self): self.mysql_user, self.mysql_password, self.mysql_host, - self.mysql_port - ) + self.mysql_port) logger.debug("Trying to flush logs") status, output = subprocess.getstatusoutput(new_command) @@ -298,10 +313,16 @@ def full_backup(self): if status == 0: logger.debug(output) # logger.debug(output[-27:]) + if self.tag is not None: + logger.debug("Adding backup tags") + self.add_tag(self.backupdir, self.recent_full_backup_file(), 'Full', self.tag, 'OK') return True else: logger.error("FAILED: FULL BACKUP") logger.error(output) + if self.tag is not None: + logger.debug("Adding backup tags") + self.add_tag(self.backupdir, self.recent_full_backup_file(), 'Full', self.tag, 'FAILED') raise RuntimeError("FAILED: FULL BACKUP") def inc_backup(self): @@ -459,11 +480,17 @@ def inc_backup(self): if status == 0: logger.debug(output) # logger.debug(output[-27:]) + if self.tag is not None: + logger.debug("Adding backup tags") + self.add_tag(self.backupdir, self.recent_inc_backup_file(), 'Inc', self.tag, 'OK') return True else: - logger.error("FAILED: INCREMENT BACKUP FAILED!") + logger.error("FAILED: INCREMENTAL BACKUP") logger.error(output) - raise RuntimeError("FAILED: INCREMENT BACKUP FAILED!") + if self.tag is not None: + logger.debug("Adding backup tags") + self.add_tag(self.backupdir, self.recent_inc_backup_file(), 'Inc', self.tag, 'FAILED') + raise RuntimeError("FAILED: INCREMENTAL BACKUP") else: # If there is already existing incremental backup @@ -607,10 +634,16 @@ def inc_backup(self): if status == 0: logger.debug(output) # logger.debug(output[-27:]) + if self.tag is not None: + logger.debug("Adding backup tags") + self.add_tag(self.backupdir, self.recent_inc_backup_file(), 'Inc', self.tag, 'OK') return True else: logger.error("FAILED: INCREMENT BACKUP") logger.error(output) + if self.tag is not None: + logger.debug("Adding backup tags") + self.add_tag(self.backupdir, self.recent_inc_backup_file(), 'Inc', self.tag, 'FAILED') raise RuntimeError("FAILED: INCREMENT BACKUP") def all_backup(self): diff --git a/test/conftest.py b/test/conftest.py index f284f378..6bb13cc5 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -3,6 +3,7 @@ from prepare_env_test_mode.run_benchmark import RunBenchmark from prepare_env_test_mode.config_generator import ConfigGenerator from prepare_env_test_mode.runner_test_mode import RunnerTestMode +from master_backup_script.backuper import Backup clb_obj = CloneBuildStartServer() diff --git a/test/test_backup.py b/test/test_backup.py new file mode 100644 index 00000000..64340e8c --- /dev/null +++ b/test/test_backup.py @@ -0,0 +1,30 @@ +# PyTest file for testing Backup class +from master_backup_script.backuper import Backup +from general_conf.generalops import GeneralClass + +class TestBackup: + + def test_add_tag(self): + # Method for checking the add_tag() static method. All parameters are hard coded. + gen_obj = GeneralClass() + for conf_files in gen_obj.xb_configs.split(): + if '2_3' in conf_files and '5_6' in conf_files: + obj = Backup(config='{}/{}'.format(gen_obj.testpath, conf_files), dry_run=0, tag="My first full backup") + backup_name = obj.recent_full_backup_file() + obj.add_tag(backup_dir=obj.backupdir, backup_name=backup_name, type='Full', tag_string=obj.tag) + + def test_full_backup(self): + # Method for running full_backup() + gen_obj = GeneralClass() + for conf_files in gen_obj.xb_configs.split(): + if '2_3' in conf_files and '5_6' in conf_files: + obj = Backup(config='{}/{}'.format(gen_obj.testpath, conf_files), dry_run=0, tag="My first full backup") + obj.full_backup() + + def test_inc_backup(self): + # Method for running inc_backup() + gen_obj = GeneralClass() + for conf_files in gen_obj.xb_configs.split(): + if '2_3' in conf_files and '5_6' in conf_files: + obj = Backup(config='{}/{}'.format(gen_obj.testpath, conf_files), dry_run=0, tag="My first inc backup") + obj.inc_backup() diff --git a/test/test_prepare_backup.py b/test/test_test_prepare_backup.py similarity index 97% rename from test/test_prepare_backup.py rename to test/test_test_prepare_backup.py index bc85a720..da67d76b 100644 --- a/test/test_prepare_backup.py +++ b/test/test_test_prepare_backup.py @@ -1,6 +1,7 @@ from general_conf.generalops import GeneralClass from prepare_env_test_mode.prepare_backup import WrapperForPrepareTest +# Part of TEST MODE class TestPrepareBackup: # class for prepare_env_test_mode.prepare_backup.py diff --git a/test/test_take_backup.py b/test/test_test_take_backup.py similarity index 95% rename from test/test_take_backup.py rename to test/test_test_take_backup.py index a17896f1..c25e184a 100644 --- a/test/test_take_backup.py +++ b/test/test_test_take_backup.py @@ -2,6 +2,8 @@ from prepare_env_test_mode.take_backup import WrapperForBackupTest from general_conf.generalops import GeneralClass +# Part of TEST MODE + class TestTakeBackup: # Test class for take_backup.py