mirror of
https://gitlab.com/crafty-controller/crafty-4.git
synced 2024-08-30 18:23:09 +00:00
Implement basic logic to trigger snapshots through Crafty.
This commit is contained in:
parent
e6a577c172
commit
2e47d5b21e
@ -1,3 +1,6 @@
|
||||
import base64
|
||||
|
||||
|
||||
class CryptoHelper:
|
||||
def __init__(self, helper):
|
||||
self.helper = helper
|
||||
@ -5,3 +8,7 @@ class CryptoHelper:
|
||||
|
||||
def say_hello_world(self):
|
||||
print(self.test)
|
||||
|
||||
@staticmethod
|
||||
def bytes_to_b64(input_bytes: bytes) -> str:
|
||||
return base64.b64encode(input_bytes).decode("UTF-8").rstrip("\n")
|
||||
|
@ -117,6 +117,7 @@ class Backups(BaseModel):
|
||||
default = BooleanField(default=False)
|
||||
status = CharField(default='{"status": "Standby", "message": ""}')
|
||||
enabled = BooleanField(default=True)
|
||||
backup_type = CharField(default="zip_archive")
|
||||
|
||||
class Meta:
|
||||
table_name = "backups"
|
||||
@ -368,6 +369,7 @@ class HelpersManagement:
|
||||
"after": backup.after,
|
||||
"default": backup.default,
|
||||
"enabled": backup.enabled,
|
||||
"backup_type": backup.backup_type,
|
||||
}
|
||||
else:
|
||||
data = Backups.select().where(Backups.server_id == server_id).execute()
|
||||
@ -375,13 +377,10 @@ class HelpersManagement:
|
||||
|
||||
@staticmethod
|
||||
def get_default_server_backup(server_id: str) -> dict:
|
||||
print(server_id)
|
||||
bu_query = Backups.select().where(
|
||||
Backups.server_id == server_id,
|
||||
Backups.default == True, # pylint: disable=singleton-comparison
|
||||
)
|
||||
for item in bu_query:
|
||||
print("HI", item)
|
||||
backup_model = bu_query.first()
|
||||
|
||||
if backup_model:
|
||||
|
@ -3,6 +3,7 @@ import time
|
||||
import datetime
|
||||
import json
|
||||
import logging
|
||||
import pathlib
|
||||
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
@ -35,11 +36,13 @@ class BackupManager:
|
||||
self.tz = ZoneInfo("Europe/London")
|
||||
|
||||
def backup_starter(self, backup_config, server):
|
||||
if backup_config.get("type", "zip_vault") == "zip_vault":
|
||||
self.zip_vault(backup_config, server)
|
||||
|
||||
def zip_vault(self, backup_config, server):
|
||||
"""Notify users of backup starting, and start the backup.
|
||||
|
||||
Args:
|
||||
backup_config (_type_): _description_
|
||||
server (_type_): Server object to backup
|
||||
"""
|
||||
# Notify users of backup starting
|
||||
logger.info(f"Starting server {server.name}" f" (ID {server.server_id}) backup")
|
||||
server_users = PermissionsServers.get_server_user_list(server.server_id)
|
||||
# Alert the start of the backup to the authorized users.
|
||||
@ -53,6 +56,14 @@ class BackupManager:
|
||||
)
|
||||
time.sleep(3)
|
||||
|
||||
# Start the backup
|
||||
if backup_config.get("backup_type", "zip_vault") == "zip_vault":
|
||||
self.zip_vault(backup_config, server)
|
||||
else:
|
||||
self.snapshot_backup(backup_config, server)
|
||||
|
||||
def zip_vault(self, backup_config, server):
|
||||
|
||||
# Adjust the location to include the backup ID for destination.
|
||||
backup_location = os.path.join(
|
||||
backup_config["backup_location"], backup_config["backup_id"]
|
||||
@ -126,32 +137,35 @@ class BackupManager:
|
||||
)
|
||||
time.sleep(5)
|
||||
except Exception as e:
|
||||
logger.exception(
|
||||
"Failed to create backup of server"
|
||||
f" {server.name} (ID {server.server_id})"
|
||||
)
|
||||
results = {
|
||||
"percent": 100,
|
||||
"total_files": 0,
|
||||
"current_file": 0,
|
||||
"backup_id": backup_config["backup_id"],
|
||||
}
|
||||
if len(WebSocketManager().clients) > 0:
|
||||
WebSocketManager().broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": str(server.server_id)},
|
||||
"backup_status",
|
||||
results,
|
||||
)
|
||||
|
||||
HelpersManagement.update_backup_config(
|
||||
backup_config["backup_id"],
|
||||
{"status": json.dumps({"status": "Failed", "message": f"{e}"})},
|
||||
)
|
||||
self.fail_backup(e, backup_config, server)
|
||||
server.backup_server(
|
||||
backup_config,
|
||||
)
|
||||
|
||||
def fail_backup(self, why: Exception, backup_config: dict, server):
|
||||
logger.exception(
|
||||
"Failed to create backup of server"
|
||||
f" {server.name} (ID {server.server_id})"
|
||||
)
|
||||
results = {
|
||||
"percent": 100,
|
||||
"total_files": 0,
|
||||
"current_file": 0,
|
||||
"backup_id": backup_config["backup_id"],
|
||||
}
|
||||
if len(WebSocketManager().clients) > 0:
|
||||
WebSocketManager().broadcast_page_params(
|
||||
"/panel/server_detail",
|
||||
{"id": str(server.server_id)},
|
||||
"backup_status",
|
||||
results,
|
||||
)
|
||||
|
||||
HelpersManagement.update_backup_config(
|
||||
backup_config["backup_id"],
|
||||
{"status": json.dumps({"status": "Failed", "message": f"{why}"})},
|
||||
)
|
||||
|
||||
def list_backups(self, backup_config: dict, server_id) -> list:
|
||||
if not backup_config:
|
||||
logger.info(
|
||||
@ -197,3 +211,37 @@ class BackupManager:
|
||||
)
|
||||
logger.info(f"Removing old backup '{oldfile['path']}'")
|
||||
os.remove(Helpers.get_os_understandable_path(oldfile_path))
|
||||
|
||||
def snapshot_backup(self, backup_config, server):
|
||||
|
||||
logger.info(f"Starting snapshot style backup for {server.name}")
|
||||
|
||||
# Adjust the location to include the backup ID for destination.
|
||||
backup_location = os.path.join(
|
||||
pathlib.Path(backup_config["backup_location"]), "snapshot_backups"
|
||||
)
|
||||
try:
|
||||
self.ensure_snapshot_directory_is_valid(backup_location)
|
||||
except PermissionError as why:
|
||||
self.fail_backup(why, backup_config, server)
|
||||
|
||||
def ensure_snapshot_directory_is_valid(self, backup_path: pathlib.Path) -> bool:
|
||||
backup_path.mkdir(exist_ok=True)
|
||||
backup_readme_path = backup_path / "README.txt"
|
||||
|
||||
if not backup_readme_path.exists():
|
||||
logger.info("Is this doing anything?")
|
||||
try:
|
||||
logger.info("Attempting to make snapshot storage directory.")
|
||||
with open(backup_readme_path, "w", encoding="UTF-8") as f:
|
||||
f.write(
|
||||
"Crafty snapshot backup storage dir. Please do not touch"
|
||||
"these files."
|
||||
)
|
||||
|
||||
except PermissionError as why:
|
||||
raise PermissionError(
|
||||
f"Unable to write to snapshot backup storage path"
|
||||
f": {backup_readme_path}"
|
||||
) from why
|
||||
return True
|
||||
|
@ -30,6 +30,12 @@ BACKUP_PATCH_SCHEMA = {
|
||||
"before": {"type": "string"},
|
||||
"after": {"type": "string"},
|
||||
"excluded_dirs": {"type": "array"},
|
||||
"backup_type": {
|
||||
"type": "string",
|
||||
"enum": ["zip_vault", "snapshot"],
|
||||
"error": "enumErr",
|
||||
"fill": True,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
@ -45,6 +51,12 @@ BASIC_BACKUP_PATCH_SCHEMA = {
|
||||
"before": {"type": "string"},
|
||||
"after": {"type": "string"},
|
||||
"excluded_dirs": {"type": "array"},
|
||||
"backup_type": {
|
||||
"type": "string",
|
||||
"enum": ["zip_vault", "snapshot"],
|
||||
"error": "enumErr",
|
||||
"fill": True,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
|
@ -19,6 +19,12 @@ backup_patch_schema = {
|
||||
"before": {"type": "string"},
|
||||
"after": {"type": "string"},
|
||||
"excluded_dirs": {"type": "array"},
|
||||
"backup_type": {
|
||||
"type": "string",
|
||||
"enum": ["zip_vault", "snapshot"],
|
||||
"error": "enumErr",
|
||||
"fill": True,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
@ -34,6 +40,12 @@ basic_backup_patch_schema = {
|
||||
"before": {"type": "string"},
|
||||
"after": {"type": "string"},
|
||||
"excluded_dirs": {"type": "array"},
|
||||
"backup_type": {
|
||||
"type": "string",
|
||||
"enum": ["zip_vault", "snapshot"],
|
||||
"error": "enumErr",
|
||||
"fill": True,
|
||||
},
|
||||
},
|
||||
"additionalProperties": False,
|
||||
"minProperties": 1,
|
||||
|
@ -73,8 +73,7 @@
|
||||
data['lang']) }} </th>
|
||||
<th scope="col" style="width: 50%; min-width: 50px;">{{ translate('serverBackups',
|
||||
'storageLocation', data['lang']) }}</th>
|
||||
<th scope="col" style="width: 10%; min-width: 50px;">{{ translate('serverBackups',
|
||||
'maxBackups', data['lang']) }}</th>
|
||||
<th scope="col" style="width: 10%; min-width: 50px;">Backup Type</th>
|
||||
<th scope="col" style="width: 10%; min-width: 50px;">{{ translate('serverBackups', 'actions',
|
||||
data['lang']) }}</th>
|
||||
</tr>
|
||||
@ -102,8 +101,8 @@
|
||||
<td id="{{backup.backup_location}}" class="type">
|
||||
<p style="overflow: scroll;" class="no-scroll">{{backup.backup_location}}</p>
|
||||
</td>
|
||||
<td id="{{backup.max_backups}}" class="trigger" style="overflow: scroll; max-width: 30px;">
|
||||
<p>{{backup.max_backups}}</p>
|
||||
<td id="{{backup.max_backups}}_{{backup.backup_id}}" class="trigger" style="overflow: scroll; max-width: 30px;">
|
||||
<p>{{backup.backup_type}}</p>
|
||||
</td>
|
||||
<td id="backup_edit" class="action">
|
||||
<button
|
||||
|
@ -76,6 +76,10 @@
|
||||
placeholder="{{ translate('serverBackups', 'myBackup', data['lang']) }}">
|
||||
{% end %}
|
||||
<br>
|
||||
<input type="radio" class="form-check-input" name="backup_type" id="zip_archive" value="zip_archive" checked>
|
||||
<label for="True">Full Zip Archive</label><br>
|
||||
<input type="radio" class="form-check-input" name="backup_type" id="zip_archive" value="snapshot">
|
||||
<label for="True">Snapshot</label><br>
|
||||
<br>
|
||||
{% if data['super_user'] %}
|
||||
<label for="server_name">{{ translate('serverBackups', 'storageLocation', data['lang']) }} <small
|
||||
|
16
app/migrations/20240811_snapshot_backups.py
Normal file
16
app/migrations/20240811_snapshot_backups.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by database migrator
|
||||
import peewee
|
||||
|
||||
|
||||
def migrate(migrator, database, **kwargs):
|
||||
"""
|
||||
Write your migrations here.
|
||||
"""
|
||||
migrator.add_columns("backups", backup_type=peewee.CharField(default="zip_archive"))
|
||||
|
||||
|
||||
def rollback(migrator, database, **kwargs):
|
||||
"""
|
||||
Write your rollback migrations here.
|
||||
"""
|
||||
migrator.drop_columns("backups", ["backup_type"])
|
Loading…
Reference in New Issue
Block a user