Enhance backup functionality with slim backup exclusions and update provisioning script for improved installation process
This commit is contained in:
+70
-3
@@ -835,6 +835,54 @@ def _collect_instance_logs(subdomain: str) -> tuple[bool, str]:
|
|||||||
return _run_command(command, cwd=instance_dir, timeout=180)
|
return _run_command(command, cwd=instance_dir, timeout=180)
|
||||||
|
|
||||||
|
|
||||||
|
SLIM_BACKUP_EXCLUDE_DIRS = {
|
||||||
|
".git",
|
||||||
|
".github",
|
||||||
|
"logs",
|
||||||
|
"certs",
|
||||||
|
"test-data",
|
||||||
|
"__pycache__",
|
||||||
|
".pytest_cache",
|
||||||
|
".mypy_cache",
|
||||||
|
"node_modules",
|
||||||
|
".venv",
|
||||||
|
"venv",
|
||||||
|
"tmp",
|
||||||
|
"temp",
|
||||||
|
}
|
||||||
|
|
||||||
|
SLIM_BACKUP_EXCLUDE_FILES = {
|
||||||
|
".env",
|
||||||
|
".env.local",
|
||||||
|
".env.production",
|
||||||
|
}
|
||||||
|
|
||||||
|
SLIM_BACKUP_EXCLUDE_SUFFIXES = (
|
||||||
|
".log",
|
||||||
|
".tmp",
|
||||||
|
".cache",
|
||||||
|
".pid",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_excluded_from_slim_backup(rel_path: str, is_dir: bool) -> bool:
|
||||||
|
parts = [p for p in rel_path.split(os.sep) if p and p != "."]
|
||||||
|
if not parts:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if any(part in SLIM_BACKUP_EXCLUDE_DIRS for part in parts):
|
||||||
|
return True
|
||||||
|
|
||||||
|
name = parts[-1]
|
||||||
|
if not is_dir and name in SLIM_BACKUP_EXCLUDE_FILES:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not is_dir and name.lower().endswith(SLIM_BACKUP_EXCLUDE_SUFFIXES):
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _build_instance_backup_archive(subdomain: str) -> tuple[bool, str, str | None]:
|
def _build_instance_backup_archive(subdomain: str) -> tuple[bool, str, str | None]:
|
||||||
instance_dir = _resolve_instance_dir(subdomain)
|
instance_dir = _resolve_instance_dir(subdomain)
|
||||||
if not instance_dir:
|
if not instance_dir:
|
||||||
@@ -842,14 +890,33 @@ def _build_instance_backup_archive(subdomain: str) -> tuple[bool, str, str | Non
|
|||||||
|
|
||||||
safe_name = _slugify_subdomain(subdomain)
|
safe_name = _slugify_subdomain(subdomain)
|
||||||
stamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
|
stamp = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
|
||||||
archive_base = os.path.join(tempfile.gettempdir(), f"instance-backup-{safe_name}-{stamp}")
|
archive_path = os.path.join(tempfile.gettempdir(), f"instance-backup-{safe_name}-{stamp}.tar.gz")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
archive_path = shutil.make_archive(archive_base, "gztar", root_dir=instance_dir)
|
with tarfile.open(archive_path, "w:gz") as tf:
|
||||||
|
for root, dirs, files in os.walk(instance_dir):
|
||||||
|
rel_root = os.path.relpath(root, instance_dir)
|
||||||
|
if rel_root == ".":
|
||||||
|
rel_root = ""
|
||||||
|
|
||||||
|
kept_dirs = []
|
||||||
|
for dirname in dirs:
|
||||||
|
rel_dir = os.path.join(rel_root, dirname) if rel_root else dirname
|
||||||
|
if _is_excluded_from_slim_backup(rel_dir, is_dir=True):
|
||||||
|
continue
|
||||||
|
kept_dirs.append(dirname)
|
||||||
|
dirs[:] = kept_dirs
|
||||||
|
|
||||||
|
for filename in files:
|
||||||
|
rel_file = os.path.join(rel_root, filename) if rel_root else filename
|
||||||
|
if _is_excluded_from_slim_backup(rel_file, is_dir=False):
|
||||||
|
continue
|
||||||
|
full_path = os.path.join(root, filename)
|
||||||
|
tf.add(full_path, arcname=rel_file)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return False, f"Backup-Archiv konnte nicht erstellt werden: {exc}", None
|
return False, f"Backup-Archiv konnte nicht erstellt werden: {exc}", None
|
||||||
|
|
||||||
filename = f"instance-{safe_name}-backup-{stamp}.tar.gz"
|
filename = f"instance-{safe_name}-slim-backup-{stamp}.tar.gz"
|
||||||
return True, filename, archive_path
|
return True, filename, archive_path
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -237,10 +237,14 @@ run_instance_start() {
|
|||||||
setup_or_update_repo() {
|
setup_or_update_repo() {
|
||||||
local target_dir="$1"
|
local target_dir="$1"
|
||||||
local repo_url="$2"
|
local repo_url="$2"
|
||||||
|
local installer_url="https://raw.githubusercontent.com/AIIrondev/legendary-octo-garbanzo/main/install.sh"
|
||||||
|
local installer_script=""
|
||||||
|
|
||||||
if [ -d "$target_dir/.git" ]; then
|
if [ -f "$target_dir/start.sh" ]; then
|
||||||
git -C "$target_dir" fetch --all --prune
|
# Existing installation: keep it docker-only and update via project tooling.
|
||||||
git -C "$target_dir" pull --ff-only origin main || true
|
if [ -x "$target_dir/update.sh" ]; then
|
||||||
|
(cd "$target_dir" && bash ./update.sh >/dev/null 2>&1 || true)
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -249,7 +253,24 @@ setup_or_update_repo() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$target_dir"
|
mkdir -p "$target_dir"
|
||||||
git clone "$repo_url" "$target_dir"
|
installer_script="$(mktemp)"
|
||||||
|
if ! wget -qO- "$installer_url" > "$installer_script"; then
|
||||||
|
rm -f "$installer_script"
|
||||||
|
fail "Installer konnte nicht geladen werden: $installer_url"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Patch only the target directory variable so we can install per instance.
|
||||||
|
if ! sed -i "s|^PROJECT_DIR=.*$|PROJECT_DIR=\"$target_dir\"|" "$installer_script"; then
|
||||||
|
rm -f "$installer_script"
|
||||||
|
fail "Installer konnte nicht vorbereitet werden."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! bash "$installer_script" --skip-cleanup-old; then
|
||||||
|
rm -f "$installer_script"
|
||||||
|
fail "Installer-Ausführung fehlgeschlagen."
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$installer_script"
|
||||||
}
|
}
|
||||||
|
|
||||||
write_nginx_site() {
|
write_nginx_site() {
|
||||||
@@ -442,9 +463,9 @@ is_valid_subdomain "$SUBDOMAIN" || fail "Ungueltige Subdomain: $SUBDOMAIN"
|
|||||||
INSTANCE_DIR="$BASE_DIR/$SUBDOMAIN"
|
INSTANCE_DIR="$BASE_DIR/$SUBDOMAIN"
|
||||||
FULL_DOMAIN="$SUBDOMAIN.$PARENT_DOMAIN"
|
FULL_DOMAIN="$SUBDOMAIN.$PARENT_DOMAIN"
|
||||||
|
|
||||||
require_cmd git
|
|
||||||
require_cmd docker
|
require_cmd docker
|
||||||
require_cmd bash
|
require_cmd bash
|
||||||
|
require_cmd wget
|
||||||
|
|
||||||
mkdir -p "$BASE_DIR"
|
mkdir -p "$BASE_DIR"
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,7 @@
|
|||||||
<input type="hidden" name="subdomain" value="{{ item.subdomain }}">
|
<input type="hidden" name="subdomain" value="{{ item.subdomain }}">
|
||||||
<button type="submit">Backup</button>
|
<button type="submit">Backup</button>
|
||||||
</form>
|
</form>
|
||||||
<a class="action-link" href="{{ url_for('admin_export_instance_backup', subdomain=item.subdomain) }}">Backup exportieren</a>
|
<a class="action-link" href="{{ url_for('admin_export_instance_backup', subdomain=item.subdomain) }}">Slim-Backup exportieren</a>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="update_instance">
|
<input type="hidden" name="action" value="update_instance">
|
||||||
<input type="hidden" name="subdomain" value="{{ item.subdomain }}">
|
<input type="hidden" name="subdomain" value="{{ item.subdomain }}">
|
||||||
|
|||||||
+26
-5
@@ -229,10 +229,14 @@ run_instance_start() {
|
|||||||
setup_or_update_repo() {
|
setup_or_update_repo() {
|
||||||
local target_dir="$1"
|
local target_dir="$1"
|
||||||
local repo_url="$2"
|
local repo_url="$2"
|
||||||
|
local installer_url="https://raw.githubusercontent.com/AIIrondev/legendary-octo-garbanzo/main/install.sh"
|
||||||
|
local installer_script=""
|
||||||
|
|
||||||
if [ -d "$target_dir/.git" ]; then
|
if [ -f "$target_dir/start.sh" ]; then
|
||||||
git -C "$target_dir" fetch --all --prune
|
# Existing installation: keep it docker-only and update via project tooling.
|
||||||
git -C "$target_dir" pull --ff-only origin main || true
|
if [ -x "$target_dir/update.sh" ]; then
|
||||||
|
(cd "$target_dir" && bash ./update.sh >/dev/null 2>&1 || true)
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -241,7 +245,24 @@ setup_or_update_repo() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$target_dir"
|
mkdir -p "$target_dir"
|
||||||
git clone "$repo_url" "$target_dir"
|
installer_script="$(mktemp)"
|
||||||
|
if ! wget -qO- "$installer_url" > "$installer_script"; then
|
||||||
|
rm -f "$installer_script"
|
||||||
|
fail "Installer konnte nicht geladen werden: $installer_url"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Patch only the target directory variable so we can install per instance.
|
||||||
|
if ! sed -i "s|^PROJECT_DIR=.*$|PROJECT_DIR=\"$target_dir\"|" "$installer_script"; then
|
||||||
|
rm -f "$installer_script"
|
||||||
|
fail "Installer konnte nicht vorbereitet werden."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! bash "$installer_script" --skip-cleanup-old; then
|
||||||
|
rm -f "$installer_script"
|
||||||
|
fail "Installer-Ausführung fehlgeschlagen."
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$installer_script"
|
||||||
}
|
}
|
||||||
|
|
||||||
write_nginx_site() {
|
write_nginx_site() {
|
||||||
@@ -434,9 +455,9 @@ is_valid_subdomain "$SUBDOMAIN" || fail "Ungueltige Subdomain: $SUBDOMAIN"
|
|||||||
INSTANCE_DIR="$BASE_DIR/$SUBDOMAIN"
|
INSTANCE_DIR="$BASE_DIR/$SUBDOMAIN"
|
||||||
FULL_DOMAIN="$SUBDOMAIN.$PARENT_DOMAIN"
|
FULL_DOMAIN="$SUBDOMAIN.$PARENT_DOMAIN"
|
||||||
|
|
||||||
require_cmd git
|
|
||||||
require_cmd docker
|
require_cmd docker
|
||||||
require_cmd bash
|
require_cmd bash
|
||||||
|
require_cmd wget
|
||||||
|
|
||||||
mkdir -p "$BASE_DIR"
|
mkdir -p "$BASE_DIR"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user