Merge branch 'bugfix/backup-migration' into 'dev'

Orphan Backup Migration Fix

See merge request crafty-controller/crafty-4!785
This commit is contained in:
Iain Powrie 2024-08-06 19:05:17 +00:00
commit fe33b84e10
6 changed files with 64 additions and 19 deletions

View File

@ -1,12 +1,16 @@
# Changelog # Changelog
## --- [4.4.1] - 2024/TBD ## --- [4.4.1] - 2024/08/06
### Patch Fixes
- Migrations | Fix orphan backup configurations crashing migration operation ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/785))
- Migrations | Fix missing default configuration if no server backup config exists during the migration ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/785))
- Migrations | Fix extended runtime on move procedure during migration ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/785))
**-----------------------------------------------------------------------------** **-----------------------------------------------------------------------------**
**Initial release was reverted for patching (See Merge Request: [!784](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/784))** **Initial release was reverted for patching (See Merge Request: [!784](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/784))** *2024/07/28*
**-----------------------------------------------------------------------------** **-----------------------------------------------------------------------------**### Refactor
### Refactor
- Backups | Allow multiple backup configurations ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/711)) - Backups | Allow multiple backup configurations ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/711))
- UploadAPI | Use Crafty's JWT authentication for file uploads ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/762)) - UploadAPI | Use Crafty's JWT authentication for file uploads ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/762))
- UploadAPI | Splice files on the frontend to allow chunked uploads as well as bulk uploads ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/762)) - UploadAPI | Splice files on the frontend to allow chunked uploads as well as bulk uploads ([Merge Request](https://gitlab.com/crafty-controller/crafty-4/-/merge_requests/762))

View File

@ -400,6 +400,8 @@ class HelpersManagement:
if "excluded_dirs" in conf: if "excluded_dirs" in conf:
dirs_to_exclude = ",".join(conf["excluded_dirs"]) dirs_to_exclude = ",".join(conf["excluded_dirs"])
conf["excluded_dirs"] = dirs_to_exclude conf["excluded_dirs"] = dirs_to_exclude
if len(self.get_backups_by_server(conf["server_id"], True)) <= 0:
conf["default"] = True
backup = Backups.create(**conf) backup = Backups.create(**conf)
logger.debug("Creating new backup record.") logger.debug("Creating new backup record.")
return backup.backup_id return backup.backup_id

View File

@ -183,8 +183,7 @@ class FileHelpers:
@staticmethod @staticmethod
def move_dir(src_path, dest_path): def move_dir(src_path, dest_path):
FileHelpers.copy_dir(src_path, dest_path) shutil.move(src_path, dest_path)
FileHelpers.del_dirs(src_path)
@staticmethod @staticmethod
def move_dir_exist(src_path, dest_path): def move_dir_exist(src_path, dest_path):
@ -193,8 +192,7 @@ class FileHelpers:
@staticmethod @staticmethod
def move_file(src_path, dest_path): def move_file(src_path, dest_path):
FileHelpers.copy_file(src_path, dest_path) shutil.move(src_path, dest_path)
FileHelpers.del_file(src_path)
@staticmethod @staticmethod
def make_archive(path_to_destination, path_to_zip, comment=""): def make_archive(path_to_destination, path_to_zip, comment=""):

View File

@ -1373,6 +1373,19 @@ class ServerInstance:
def threaded_jar_update(self): def threaded_jar_update(self):
server_users = PermissionsServers.get_server_user_list(self.server_id) server_users = PermissionsServers.get_server_user_list(self.server_id)
# check to make sure a backup config actually exists before starting the update
if len(self.management_helper.get_backups_by_server(self.server_id, True)) <= 0:
for user in server_users:
WebSocketManager().broadcast_user(
user,
"notification",
"Backup config does not exist for "
+ self.name
+ ". canceling update.",
)
logger.error(f"Back config does not exist for {self.name}. Update Failed.")
self.stats_helper.set_update(False)
return
was_started = "-1" was_started = "-1"
# Get default backup configuration # Get default backup configuration
backup_config = HelpersManagement.get_default_server_backup(self.server_id) backup_config = HelpersManagement.get_default_server_backup(self.server_id)
@ -1428,7 +1441,8 @@ class ServerInstance:
"notification", "notification",
"Backup failed for " + self.name + ". canceling update.", "Backup failed for " + self.name + ". canceling update.",
) )
return False self.stats_helper.set_update(False)
return
# lets download the files # lets download the files
if HelperServers.get_server_type_by_id(self.server_id) != "minecraft-bedrock": if HelperServers.get_server_type_by_id(self.server_id) != "minecraft-bedrock":

View File

@ -58,8 +58,7 @@
<div class="card-body"> <div class="card-body">
{% if len(data['backups']) == 0 %} {% if len(data['backups']) == 0 %}
<div style="text-align: center; color: grey;"> <div style="text-align: center; color: grey;">
<h7>{{ translate('serverBackups', 'no-backup', data['lang']) }} <strong>{{ <h7>{{ translate('serverBackups', 'no-backup', data['lang']) }}.</h7>
translate('serverBackups', 'newBackup',data['lang']) }}</strong>.</h7>
</div> </div>
{% end %} {% end %}
{% if len(data['backups']) > 0 %} {% if len(data['backups']) > 0 %}

View File

@ -13,6 +13,13 @@ from app.classes.shared.file_helpers import FileHelpers
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def is_valid_backup(backup, all_servers):
try:
return str(backup.server_id) in all_servers
except (TypeError, peewee.DoesNotExist):
return False
def migrate(migrator: Migrator, database, **kwargs): def migrate(migrator: Migrator, database, **kwargs):
""" """
Write your migrations here. Write your migrations here.
@ -150,9 +157,17 @@ def migrate(migrator: Migrator, database, **kwargs):
migrator.create_table(NewSchedules) migrator.create_table(NewSchedules)
migrator.run() migrator.run()
all_servers = [
row.server_id for row in Servers.select(Servers.server_id).distinct()
]
all_backups = Backups.select()
Console.info("Cleaning up orphan backups for all servers")
valid_backups = [
backup for backup in all_backups if is_valid_backup(backup, all_servers)
]
# Copy data from the existing backups table to the new one # Copy data from the existing backups table to the new one
for backup in Backups.select(): for backup in valid_backups:
Console.info(f"Trying to get server for backup migration {backup.server_id}")
# Fetch the related server entry from the Servers table # Fetch the related server entry from the Servers table
server = Servers.get(Servers.server_id == backup.server_id) server = Servers.get(Servers.server_id == backup.server_id)
Console.info(f"Migrations: Migrating backup for server {server.server_name}") Console.info(f"Migrations: Migrating backup for server {server.server_name}")
@ -172,15 +187,28 @@ def migrate(migrator: Migrator, database, **kwargs):
default=True, default=True,
enabled=True, enabled=True,
) )
Console.info(
f"New backup table created for {server.server_name} with id {new_backup.backup_id}"
)
Helpers.ensure_dir_exists( Helpers.ensure_dir_exists(
os.path.join(server.backup_path, new_backup.backup_id) os.path.join(server.backup_path, new_backup.backup_id)
) )
for file in os.listdir(server.backup_path): try:
if not os.path.isdir(os.path.join(os.path.join(server.backup_path, file))): Console.info(
FileHelpers.move_file( f"Moving old backups to new backup dir for {server.server_name}"
os.path.join(server.backup_path, file), )
os.path.join(server.backup_path, new_backup.backup_id, file), for file in os.listdir(server.backup_path):
) if not os.path.isdir(
os.path.join(os.path.join(server.backup_path, file))
):
FileHelpers.move_file(
os.path.join(server.backup_path, file),
os.path.join(server.backup_path, new_backup.backup_id, file),
)
except FileNotFoundError as why:
logger.error(
f"Could not move backup {file} for {server.server_name} to new location with error {why}"
)
Console.debug("Migrations: Dropping old backup table") Console.debug("Migrations: Dropping old backup table")
# Drop the existing backups table # Drop the existing backups table