diff --git a/HISTORY.md b/HISTORY.md index 53f8c22..cc21289 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,3 +1,8 @@ +## v2.0.3 (2021-10-03) + +* , #449 by @ShahriyarR +* , #448 by @ShahriyarR + ## v2.0.2 (2021-05-06) * Increased code coverage and did code base refactoring, #444 by @shahriyarr diff --git a/mysql_autoxtrabackup/autoxtrabackup.py b/mysql_autoxtrabackup/autoxtrabackup.py index 3da19e0..0cc8365 100644 --- a/mysql_autoxtrabackup/autoxtrabackup.py +++ b/mysql_autoxtrabackup/autoxtrabackup.py @@ -17,6 +17,9 @@ from mysql_autoxtrabackup.backup_prepare.prepare import Prepare from mysql_autoxtrabackup.general_conf import path_config from mysql_autoxtrabackup.general_conf.generalops import GeneralClass +from mysql_autoxtrabackup.general_conf.generate_default_conf import ( + GenerateDefaultConfig, +) from mysql_autoxtrabackup.process_runner.process_runner import ProcessRunner from mysql_autoxtrabackup.utils import version @@ -103,12 +106,11 @@ def validate_file(file: str) -> Optional[bool]: # filename extension should be .cnf pattern = re.compile(r".*\.cnf") - if pattern.match(file): - # Lastly the file should have all 5 required headers - if check_file_content(file): - return None - else: + if not pattern.match(file): raise ValueError("Invalid file extension. Expecting .cnf") + # Lastly the file should have all 5 required headers + if check_file_content(file): + return None return None @@ -133,6 +135,12 @@ def validate_file(file: str) -> Optional[bool]: show_default=True, help="Read options from the given file", ) +@click.option( + "--generate-config-file", + is_flag=True, + is_eager=True, + help="Create a config file template in default directory", +) @click.option("--tag", help="Pass the tag string for each backup") @click.option("--show-tags", is_flag=True, help="Show backup tags and exit") @click.option("-v", "--verbose", is_flag=True, help="Be verbose (print to console)") @@ -188,6 +196,7 @@ def all_procedure( log_file, log, defaults_file, + generate_config_file, dry_run, log_file_max_bytes, log_file_backup_count, @@ -256,6 +265,7 @@ def all_procedure( and dry_run is False and show_tags is False and run_server is False + and generate_config_file is False ): print_help(ctx, None, value=True) @@ -264,6 +274,10 @@ def all_procedure( elif show_tags and defaults_file: backup_ = Backup(config=defaults_file) backup_.show_tags(backup_dir=str(backup_options.get("backup_dir"))) + elif generate_config_file: + gen_ = GenerateDefaultConfig() + gen_.generate_config_file() + logger.info(f"Default config file is generated in {defaults_file}") elif prepare: prepare_ = Prepare(config=defaults_file, dry_run=dry_run_, tag=tag) prepare_.prepare_backup_and_copy_back() diff --git a/mysql_autoxtrabackup/backup_backup/backup_archive.py b/mysql_autoxtrabackup/backup_backup/backup_archive.py index 51ff78e..09fa9bf 100644 --- a/mysql_autoxtrabackup/backup_backup/backup_archive.py +++ b/mysql_autoxtrabackup/backup_backup/backup_archive.py @@ -7,6 +7,7 @@ from mysql_autoxtrabackup.backup_backup.backup_builder import BackupBuilderChecker from mysql_autoxtrabackup.general_conf import path_config from mysql_autoxtrabackup.general_conf.generalops import GeneralClass +from mysql_autoxtrabackup.process_runner.errors import BackupArchiveNotConfigured from mysql_autoxtrabackup.process_runner.process_runner import ProcessRunner from mysql_autoxtrabackup.utils import helpers @@ -126,6 +127,14 @@ def clean_old_archives(self) -> None: archive_dir = str(self.backup_archive_options.get("archive_dir")) # Finding if last full backup older than the interval or more from now! cleanup_msg = "Removing archive {}/{} due to {}" + if not self.backup_archive_options.get( + "archive_max_duration", None + ) and not self.backup_archive_options.get("archive_max_size", None): + raise BackupArchiveNotConfigured( + expression="BackupArchiveNotConfigured", + message="You need to both set archive_max_size and archive_max_duration in config file.", + ) + for archive in helpers.sorted_ls(archive_dir): if "_archive" in archive: archive_date = datetime.strptime(archive, "%Y-%m-%d_%H-%M-%S_archive") diff --git a/mysql_autoxtrabackup/general_conf/generalops.py b/mysql_autoxtrabackup/general_conf/generalops.py index e446348..f670ad2 100644 --- a/mysql_autoxtrabackup/general_conf/generalops.py +++ b/mysql_autoxtrabackup/general_conf/generalops.py @@ -95,11 +95,10 @@ def backup_archive_options(self) -> Dict[str, Union[str, float]]: archive_max_size = self.con.get(section, "max_archive_size", fallback=None) if archive_max_size: archive_max_size = humanfriendly.parse_size(archive_max_size) - else: - if self.con.get(section, "archive_max_size", fallback=None): - archive_max_size = humanfriendly.parse_size( - self.con.get(section, "archive_max_size", fallback=None) - ) + elif self.con.get(section, "archive_max_size", fallback=None): + archive_max_size = humanfriendly.parse_size( + self.con.get(section, "archive_max_size", fallback=None) + ) # backward compatible with old config 'max_archive_duration' and newer 'archive_max_duration' archive_max_duration = self.con.get( @@ -107,11 +106,10 @@ def backup_archive_options(self) -> Dict[str, Union[str, float]]: ) if archive_max_duration: archive_max_duration = humanfriendly.parse_timespan(archive_max_duration) - else: - if self.con.get(section, "archive_max_size", fallback=None): - archive_max_duration = humanfriendly.parse_timespan( - self.con.get(section, "archive_max_size", fallback=None) - ) + elif self.con.get(section, "archive_max_duration", fallback=None): + archive_max_duration = humanfriendly.parse_timespan( + self.con.get(section, "archive_max_duration", fallback=None) + ) return { "archive_dir": self.con.get(section, "archive_dir", fallback=None), # type: ignore diff --git a/mysql_autoxtrabackup/process_runner/errors.py b/mysql_autoxtrabackup/process_runner/errors.py index c472318..e32d72d 100644 --- a/mysql_autoxtrabackup/process_runner/errors.py +++ b/mysql_autoxtrabackup/process_runner/errors.py @@ -55,3 +55,14 @@ def __init__(self, expression: str, message: str) -> None: self.expression = expression self.message = message log_error(self.expression, self.message) + + +class BackupArchiveNotConfigured(Error): + """ + Exception raised when archive_max_size and archive_max_duration configs are not set + """ + + def __init__(self, expression: str, message: str) -> None: + self.expression = expression + self.message = message + log_error(self.expression, self.message) diff --git a/mysql_autoxtrabackup/utils/version.py b/mysql_autoxtrabackup/utils/version.py index 2fd781c..bd41eab 100644 --- a/mysql_autoxtrabackup/utils/version.py +++ b/mysql_autoxtrabackup/utils/version.py @@ -1,3 +1,3 @@ __all__ = "VERSION" -VERSION = "2.0.2" +VERSION = "2.0.3"