Template
Add WG/AWG client config ZIP export and backup restore.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -168,3 +168,76 @@ printf '%s\n' "$archive"
|
||||
path = (out or '').strip().splitlines()[-1] if (out or '').strip() else ''
|
||||
name = path.rsplit('/', 1)[-1] if path else ''
|
||||
return {'status': 'success', 'protocol': protocol, 'backup': {'name': name, 'path': path}}
|
||||
|
||||
def restore_backup(self, protocol, container_name, filename):
|
||||
"""Restore protocol files from a previously created backup archive."""
|
||||
safe_name = self.safe_filename(filename)
|
||||
if not safe_name:
|
||||
return {'status': 'error', 'message': 'Invalid backup filename'}
|
||||
|
||||
safe_proto = self.safe_protocol(protocol)
|
||||
remote_archive = f'{self.BACKUP_ROOT}/{safe_proto}/{safe_name}'
|
||||
paths = self._paths_for(protocol, container_name)
|
||||
container_paths = ' '.join(shlex.quote(p) for p in paths['container'])
|
||||
host_paths = ' '.join(shlex.quote(p) for p in paths['host'])
|
||||
archive_q = shlex.quote(remote_archive)
|
||||
container_q = shlex.quote(str(container_name or ''))
|
||||
protocol_q = shlex.quote(str(protocol))
|
||||
|
||||
script = f"""
|
||||
set -eu
|
||||
umask 077
|
||||
archive={archive_q}
|
||||
container={container_q}
|
||||
protocol={protocol_q}
|
||||
if [ ! -f "$archive" ]; then
|
||||
echo "Backup archive not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
work_dir=$(mktemp -d /tmp/amnezia-restore-XXXXXX)
|
||||
cleanup() {{ rm -rf "$work_dir"; }}
|
||||
trap cleanup EXIT
|
||||
tar -xzf "$archive" -C "$work_dir"
|
||||
if [ ! -f "$work_dir/backup-info.json" ]; then
|
||||
echo "Invalid backup archive (missing backup-info.json)" >&2
|
||||
exit 1
|
||||
fi
|
||||
restore_host_path() {{
|
||||
src="$1"
|
||||
staged="$work_dir/host$src"
|
||||
if [ -e "$staged" ]; then
|
||||
mkdir -p "$(dirname "$src")"
|
||||
rm -rf "$src"
|
||||
cp -a "$staged" "$src"
|
||||
fi
|
||||
}}
|
||||
restore_container_path() {{
|
||||
src="$1"
|
||||
staged="$work_dir/container$src"
|
||||
if [ -n "$container" ] && [ -e "$staged" ] && docker inspect "$container" >/dev/null 2>&1; then
|
||||
if [ -d "$staged" ]; then
|
||||
docker exec "$container" mkdir -p "$src" >/dev/null 2>&1 || true
|
||||
docker cp "$staged/." "$container:$src/" >/dev/null 2>&1 || true
|
||||
else
|
||||
parent=$(dirname "$src")
|
||||
docker exec "$container" mkdir -p "$parent" >/dev/null 2>&1 || true
|
||||
docker cp "$staged" "$container:$src" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
}}
|
||||
for p in {host_paths}; do restore_host_path "$p"; done
|
||||
for p in {container_paths}; do restore_container_path "$p"; done
|
||||
if [ -n "$container" ] && docker inspect "$container" >/dev/null 2>&1; then
|
||||
docker restart "$container" >/dev/null 2>&1 || true
|
||||
# Prefer bringing the WireGuard/AWG interface back up after file restore
|
||||
if docker exec "$container" test -x /opt/amnezia/start.sh >/dev/null 2>&1; then
|
||||
docker exec "$container" /opt/amnezia/start.sh >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
printf 'restored:%s\\n' "$protocol"
|
||||
""".strip()
|
||||
|
||||
out, err, code = self.ssh.run_sudo_command(script, timeout=180)
|
||||
if code != 0:
|
||||
return {'status': 'error', 'message': err or out or 'Failed to restore backup'}
|
||||
return {'status': 'success', 'protocol': protocol, 'filename': safe_name}
|
||||
|
||||
Reference in New Issue
Block a user