Setup new backup manager

ToDo: Add legacy backups to new manager to make them more module
This commit is contained in:
= 2024-12-13 22:57:49 -05:00
parent a4256b66e8
commit bd55cdce16
3 changed files with 128 additions and 111 deletions

View File

@ -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 #################################
####################################################################################

View File

@ -1,2 +1,3 @@
class CryptoHelper:
print("hi")
def __init__(self):
return

View File

@ -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):