diff --git a/app/classes/shared/backup_mgr.py b/app/classes/shared/backup_mgr.py index c7c0c38f..0f444121 100644 --- a/app/classes/shared/backup_mgr.py +++ b/app/classes/shared/backup_mgr.py @@ -2,20 +2,24 @@ import base64 import hashlib import pathlib import shutil -import uuid import zlib +import datetime from app.classes.shared.crypto_helper import CryptoHelper +# Set byte constants +BYTE_FALSE = bytes.fromhex("00") +BYTE_TRUE = bytes.fromhex("01") + class BackupManager: def __init__(self, server_instance): self.server_instance = server_instance self.crypto_helper = CryptoHelper() - # Set byte constants - BYTE_FALSE = bytes.fromhex("00") - BYTE_TRUE = bytes.fromhex("01") + #################################################################################### + ########################## SNAPSHOT METHODS ###################################### + #################################################################################### @staticmethod def blake2_hash_bytes(bytes_to_hash: bytes) -> bytes: @@ -211,12 +215,12 @@ class BackupManager: # Compress bytes if set to true if use_compression: file_chunk = self.compress_bytes(file_chunk) - compression = self.BYTE_TRUE + compression = BYTE_TRUE else: - compression = self.BYTE_FALSE + compression = BYTE_FALSE # Placeholder for encryption - encryption = self.BYTE_FALSE + encryption = BYTE_FALSE nonce = bytes.fromhex("000000000000000000000000") # Create Chunk @@ -321,16 +325,21 @@ class BackupManager: """ return self.b64_to_bytes(input_b64).decode("utf-8") - def backup(self) -> uuid.UUID: + def backup(self, conf: dict) -> None: """ Perform the backup. - Iterate over files in source dir. Apply save function. Save file information to manifest. + Iterate over files in source dir. Apply save function. + Save file information to manifest. :return: UUID of backup. """ - # Initialize backup stuff. - backup_id = uuid.uuid4() - source_path = pathlib.Path(__file__).parent / "source_files" - repo_path = pathlib.Path(__file__).parent / "backup_repository" + # Initialize backup stuff.\ + backup_id = str( + datetime.datetime.now() + .astimezone(self.server_instance.tz) + .strftime("%Y-%m-%d_%H-%M-%S") + ) + source_path = pathlib.Path(self.server_instance.server_path) + repo_path = pathlib.Path(conf["backup_location"]) / "snapshots" manifest_path = repo_path / "manifests" / f"{str(backup_id)}.manifest" # Get list of files to backup. @@ -373,7 +382,6 @@ class BackupManager: # Backup complete manifest_file.close() - return backup_id def recover( self, @@ -505,10 +513,14 @@ class BackupManager: # Read use compression byte use_compression_byte = chunk_file.read(1) - if use_compression_byte == self.BYTE_TRUE: + if use_compression_byte == BYTE_TRUE: try: return self.decompress_bytes(chunk_file.read()) except zlib.error as why: raise RuntimeError(f"Unable to decompress file {chunk_path}.") from why else: return chunk_file.read() + + #################################################################################### + ########################## LEGACY BACKUP METHODS ################################# + #################################################################################### diff --git a/app/classes/shared/crypto_helper.py b/app/classes/shared/crypto_helper.py index 7c91620c..88f7249b 100644 --- a/app/classes/shared/crypto_helper.py +++ b/app/classes/shared/crypto_helper.py @@ -1,2 +1,3 @@ class CryptoHelper: - print("hi") + def __init__(self): + return diff --git a/app/classes/shared/server.py b/app/classes/shared/server.py index 83360fae..4b2fc253 100644 --- a/app/classes/shared/server.py +++ b/app/classes/shared/server.py @@ -1185,108 +1185,112 @@ class ServerInstance: self.helper.ensure_dir_exists(backup_location) - try: - backup_filename = ( - f"{backup_location}/" - f"{datetime.datetime.now().astimezone(self.tz).strftime('%Y-%m-%d_%H-%M-%S')}" # pylint: disable=line-too-long - ) - logger.info( - f"Creating backup of server '{self.settings['server_name']}'" - f" (ID#{self.server_id}, path={self.server_path}) " - f"at '{backup_filename}'" - ) - excluded_dirs = HelpersManagement.get_excluded_backup_dirs(backup_id) - server_dir = Helpers.get_os_understandable_path(self.settings["path"]) + if conf["snapshot"]: + self.backup_manager.backup(conf) + else: - self.file_helper.make_backup( - Helpers.get_os_understandable_path(backup_filename), - server_dir, - excluded_dirs, - self.server_id, - backup_id, - conf["backup_name"], - conf["compress"], - ) - - while ( - len(self.list_backups(conf)) > conf["max_backups"] - and conf["max_backups"] > 0 - ): - backup_list = self.list_backups(conf) - oldfile = backup_list[0] - oldfile_path = f"{backup_location}/{oldfile['path']}" - logger.info(f"Removing old backup '{oldfile['path']}'") - os.remove(Helpers.get_os_understandable_path(oldfile_path)) - - logger.info(f"Backup of server: {self.name} completed") - results = { - "percent": 100, - "total_files": 0, - "current_file": 0, - "backup_id": backup_id, - } - if len(WebSocketManager().clients) > 0: - WebSocketManager().broadcast_page_params( - "/panel/server_detail", - {"id": str(self.server_id)}, - "backup_status", - results, + try: + backup_filename = ( + f"{backup_location}/" + f"{datetime.datetime.now().astimezone(self.tz).strftime('%Y-%m-%d_%H-%M-%S')}" # pylint: disable=line-too-long ) - server_users = PermissionsServers.get_server_user_list(self.server_id) - for user in server_users: - WebSocketManager().broadcast_user( - user, - "notification", - self.helper.translation.translate( - "notify", - "backupComplete", - HelperUsers.get_user_lang_by_id(user), - ).format(self.name), - ) - if was_server_running: logger.info( - "Backup complete. User had shutdown preference. Starting server." + f"Creating backup of server '{self.settings['server_name']}'" + f" (ID#{self.server_id}, path={self.server_path}) " + f"at '{backup_filename}'" ) - self.run_threaded_server(HelperUsers.get_user_id_by_name("system")) - time.sleep(3) - if conf["after"]: - if self.check_running(): - logger.debug( - "Found running server and send command option. Sending command" + excluded_dirs = HelpersManagement.get_excluded_backup_dirs(backup_id) + server_dir = Helpers.get_os_understandable_path(self.settings["path"]) + + self.file_helper.make_backup( + Helpers.get_os_understandable_path(backup_filename), + server_dir, + excluded_dirs, + self.server_id, + backup_id, + conf["backup_name"], + conf["compress"], + ) + + while ( + len(self.list_backups(conf)) > conf["max_backups"] + and conf["max_backups"] > 0 + ): + backup_list = self.list_backups(conf) + oldfile = backup_list[0] + oldfile_path = f"{backup_location}/{oldfile['path']}" + logger.info(f"Removing old backup '{oldfile['path']}'") + os.remove(Helpers.get_os_understandable_path(oldfile_path)) + + logger.info(f"Backup of server: {self.name} completed") + results = { + "percent": 100, + "total_files": 0, + "current_file": 0, + "backup_id": backup_id, + } + if len(WebSocketManager().clients) > 0: + WebSocketManager().broadcast_page_params( + "/panel/server_detail", + {"id": str(self.server_id)}, + "backup_status", + results, ) - self.send_command(conf["after"]) - # pause to let people read message. - HelpersManagement.update_backup_config( - backup_id, - {"status": json.dumps({"status": "Standby", "message": ""})}, - ) - time.sleep(5) - except Exception as e: - logger.exception( - f"Failed to create backup of server {self.name} (ID {self.server_id})" - ) - results = { - "percent": 100, - "total_files": 0, - "current_file": 0, - "backup_id": backup_id, - } - if len(WebSocketManager().clients) > 0: - WebSocketManager().broadcast_page_params( - "/panel/server_detail", - {"id": str(self.server_id)}, - "backup_status", - results, + server_users = PermissionsServers.get_server_user_list(self.server_id) + for user in server_users: + WebSocketManager().broadcast_user( + user, + "notification", + self.helper.translation.translate( + "notify", + "backupComplete", + HelperUsers.get_user_lang_by_id(user), + ).format(self.name), + ) + if was_server_running: + logger.info( + "Backup complete. User had shutdown preference. Starting server." + ) + self.run_threaded_server(HelperUsers.get_user_id_by_name("system")) + time.sleep(3) + if conf["after"]: + if self.check_running(): + logger.debug( + "Found running server and send command option. Sending command" + ) + self.send_command(conf["after"]) + # pause to let people read message. + HelpersManagement.update_backup_config( + backup_id, + {"status": json.dumps({"status": "Standby", "message": ""})}, ) - if was_server_running: - logger.info( - "Backup complete. User had shutdown preference. Starting server." + time.sleep(5) + except Exception as e: + logger.exception( + f"Failed to create backup of server {self.name} (ID {self.server_id})" + ) + results = { + "percent": 100, + "total_files": 0, + "current_file": 0, + "backup_id": backup_id, + } + if len(WebSocketManager().clients) > 0: + WebSocketManager().broadcast_page_params( + "/panel/server_detail", + {"id": str(self.server_id)}, + "backup_status", + results, + ) + if was_server_running: + logger.info( + "Backup complete. User had shutdown preference. Starting server." + ) + self.run_threaded_server(HelperUsers.get_user_id_by_name("system")) + HelpersManagement.update_backup_config( + backup_id, + {"status": json.dumps({"status": "Failed", "message": f"{e}"})}, ) - self.run_threaded_server(HelperUsers.get_user_id_by_name("system")) - HelpersManagement.update_backup_config( - backup_id, - {"status": json.dumps({"status": "Failed", "message": f"{e}"})}, - ) self.set_backup_status() def last_backup_status(self):