mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2025-01-18 17:15:13 +01:00
Setup new backup manager
ToDo: Add legacy backups to new manager to make them more module
This commit is contained in:
parent
a4256b66e8
commit
bd55cdce16
@ -2,20 +2,24 @@ import base64
|
|||||||
import hashlib
|
import hashlib
|
||||||
import pathlib
|
import pathlib
|
||||||
import shutil
|
import shutil
|
||||||
import uuid
|
|
||||||
import zlib
|
import zlib
|
||||||
|
import datetime
|
||||||
|
|
||||||
from app.classes.shared.crypto_helper import CryptoHelper
|
from app.classes.shared.crypto_helper import CryptoHelper
|
||||||
|
|
||||||
|
# Set byte constants
|
||||||
|
BYTE_FALSE = bytes.fromhex("00")
|
||||||
|
BYTE_TRUE = bytes.fromhex("01")
|
||||||
|
|
||||||
|
|
||||||
class BackupManager:
|
class BackupManager:
|
||||||
def __init__(self, server_instance):
|
def __init__(self, server_instance):
|
||||||
self.server_instance = server_instance
|
self.server_instance = server_instance
|
||||||
self.crypto_helper = CryptoHelper()
|
self.crypto_helper = CryptoHelper()
|
||||||
|
|
||||||
# Set byte constants
|
####################################################################################
|
||||||
BYTE_FALSE = bytes.fromhex("00")
|
########################## SNAPSHOT METHODS ######################################
|
||||||
BYTE_TRUE = bytes.fromhex("01")
|
####################################################################################
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def blake2_hash_bytes(bytes_to_hash: bytes) -> bytes:
|
def blake2_hash_bytes(bytes_to_hash: bytes) -> bytes:
|
||||||
@ -211,12 +215,12 @@ class BackupManager:
|
|||||||
# Compress bytes if set to true
|
# Compress bytes if set to true
|
||||||
if use_compression:
|
if use_compression:
|
||||||
file_chunk = self.compress_bytes(file_chunk)
|
file_chunk = self.compress_bytes(file_chunk)
|
||||||
compression = self.BYTE_TRUE
|
compression = BYTE_TRUE
|
||||||
else:
|
else:
|
||||||
compression = self.BYTE_FALSE
|
compression = BYTE_FALSE
|
||||||
|
|
||||||
# Placeholder for encryption
|
# Placeholder for encryption
|
||||||
encryption = self.BYTE_FALSE
|
encryption = BYTE_FALSE
|
||||||
nonce = bytes.fromhex("000000000000000000000000")
|
nonce = bytes.fromhex("000000000000000000000000")
|
||||||
|
|
||||||
# Create Chunk
|
# Create Chunk
|
||||||
@ -321,16 +325,21 @@ class BackupManager:
|
|||||||
"""
|
"""
|
||||||
return self.b64_to_bytes(input_b64).decode("utf-8")
|
return self.b64_to_bytes(input_b64).decode("utf-8")
|
||||||
|
|
||||||
def backup(self) -> uuid.UUID:
|
def backup(self, conf: dict) -> None:
|
||||||
"""
|
"""
|
||||||
Perform the backup.
|
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.
|
:return: UUID of backup.
|
||||||
"""
|
"""
|
||||||
# Initialize backup stuff.
|
# Initialize backup stuff.\
|
||||||
backup_id = uuid.uuid4()
|
backup_id = str(
|
||||||
source_path = pathlib.Path(__file__).parent / "source_files"
|
datetime.datetime.now()
|
||||||
repo_path = pathlib.Path(__file__).parent / "backup_repository"
|
.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"
|
manifest_path = repo_path / "manifests" / f"{str(backup_id)}.manifest"
|
||||||
|
|
||||||
# Get list of files to backup.
|
# Get list of files to backup.
|
||||||
@ -373,7 +382,6 @@ class BackupManager:
|
|||||||
|
|
||||||
# Backup complete
|
# Backup complete
|
||||||
manifest_file.close()
|
manifest_file.close()
|
||||||
return backup_id
|
|
||||||
|
|
||||||
def recover(
|
def recover(
|
||||||
self,
|
self,
|
||||||
@ -505,10 +513,14 @@ class BackupManager:
|
|||||||
# Read use compression byte
|
# Read use compression byte
|
||||||
use_compression_byte = chunk_file.read(1)
|
use_compression_byte = chunk_file.read(1)
|
||||||
|
|
||||||
if use_compression_byte == self.BYTE_TRUE:
|
if use_compression_byte == BYTE_TRUE:
|
||||||
try:
|
try:
|
||||||
return self.decompress_bytes(chunk_file.read())
|
return self.decompress_bytes(chunk_file.read())
|
||||||
except zlib.error as why:
|
except zlib.error as why:
|
||||||
raise RuntimeError(f"Unable to decompress file {chunk_path}.") from why
|
raise RuntimeError(f"Unable to decompress file {chunk_path}.") from why
|
||||||
else:
|
else:
|
||||||
return chunk_file.read()
|
return chunk_file.read()
|
||||||
|
|
||||||
|
####################################################################################
|
||||||
|
########################## LEGACY BACKUP METHODS #################################
|
||||||
|
####################################################################################
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
class CryptoHelper:
|
class CryptoHelper:
|
||||||
print("hi")
|
def __init__(self):
|
||||||
|
return
|
||||||
|
@ -1185,108 +1185,112 @@ class ServerInstance:
|
|||||||
|
|
||||||
self.helper.ensure_dir_exists(backup_location)
|
self.helper.ensure_dir_exists(backup_location)
|
||||||
|
|
||||||
try:
|
if conf["snapshot"]:
|
||||||
backup_filename = (
|
self.backup_manager.backup(conf)
|
||||||
f"{backup_location}/"
|
else:
|
||||||
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"])
|
|
||||||
|
|
||||||
self.file_helper.make_backup(
|
try:
|
||||||
Helpers.get_os_understandable_path(backup_filename),
|
backup_filename = (
|
||||||
server_dir,
|
f"{backup_location}/"
|
||||||
excluded_dirs,
|
f"{datetime.datetime.now().astimezone(self.tz).strftime('%Y-%m-%d_%H-%M-%S')}" # pylint: disable=line-too-long
|
||||||
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,
|
|
||||||
)
|
)
|
||||||
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(
|
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"))
|
excluded_dirs = HelpersManagement.get_excluded_backup_dirs(backup_id)
|
||||||
time.sleep(3)
|
server_dir = Helpers.get_os_understandable_path(self.settings["path"])
|
||||||
if conf["after"]:
|
|
||||||
if self.check_running():
|
self.file_helper.make_backup(
|
||||||
logger.debug(
|
Helpers.get_os_understandable_path(backup_filename),
|
||||||
"Found running server and send command option. Sending command"
|
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"])
|
server_users = PermissionsServers.get_server_user_list(self.server_id)
|
||||||
# pause to let people read message.
|
for user in server_users:
|
||||||
HelpersManagement.update_backup_config(
|
WebSocketManager().broadcast_user(
|
||||||
backup_id,
|
user,
|
||||||
{"status": json.dumps({"status": "Standby", "message": ""})},
|
"notification",
|
||||||
)
|
self.helper.translation.translate(
|
||||||
time.sleep(5)
|
"notify",
|
||||||
except Exception as e:
|
"backupComplete",
|
||||||
logger.exception(
|
HelperUsers.get_user_lang_by_id(user),
|
||||||
f"Failed to create backup of server {self.name} (ID {self.server_id})"
|
).format(self.name),
|
||||||
)
|
)
|
||||||
results = {
|
if was_server_running:
|
||||||
"percent": 100,
|
logger.info(
|
||||||
"total_files": 0,
|
"Backup complete. User had shutdown preference. Starting server."
|
||||||
"current_file": 0,
|
)
|
||||||
"backup_id": backup_id,
|
self.run_threaded_server(HelperUsers.get_user_id_by_name("system"))
|
||||||
}
|
time.sleep(3)
|
||||||
if len(WebSocketManager().clients) > 0:
|
if conf["after"]:
|
||||||
WebSocketManager().broadcast_page_params(
|
if self.check_running():
|
||||||
"/panel/server_detail",
|
logger.debug(
|
||||||
{"id": str(self.server_id)},
|
"Found running server and send command option. Sending command"
|
||||||
"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": ""})},
|
||||||
)
|
)
|
||||||
if was_server_running:
|
time.sleep(5)
|
||||||
logger.info(
|
except Exception as e:
|
||||||
"Backup complete. User had shutdown preference. Starting server."
|
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()
|
self.set_backup_status()
|
||||||
|
|
||||||
def last_backup_status(self):
|
def last_backup_status(self):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user