New packages: - secubox-app-backup: Unified backup for LXC containers, UCI config, services - luci-app-backup: KISS dashboard with container list and backup history - secubox-app-mailserver: Custom Postfix+Dovecot in LXC with mesh backup Enhanced dnsctl with: - generate: Auto-create subdomain A records - suggest: Name suggestions by category - mail-setup: MX, SPF, DMARC record creation - dkim-add: DKIM TXT record management Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
241 lines
5.7 KiB
Bash
241 lines
5.7 KiB
Bash
#!/bin/sh
|
|
# SecuBox Backup Manager RPCD Handler
|
|
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
BACKUP_CMD="/usr/sbin/secubox-backup"
|
|
|
|
case "$1" in
|
|
list)
|
|
cat <<-EOF
|
|
{
|
|
"status": {},
|
|
"list": { "type": "string" },
|
|
"container_list": {},
|
|
"create": { "type": "string" },
|
|
"restore": { "file": "string", "dry_run": "boolean" },
|
|
"cleanup": {},
|
|
"container_backup": { "name": "string" },
|
|
"container_restore": { "name": "string", "file": "string" }
|
|
}
|
|
EOF
|
|
;;
|
|
|
|
call)
|
|
case "$2" in
|
|
status)
|
|
json_init
|
|
|
|
# Get storage info
|
|
local storage=$($BACKUP_CMD status 2>/dev/null | grep "Storage Path" | cut -d: -f2 | tr -d ' ')
|
|
local used=$($BACKUP_CMD status 2>/dev/null | grep "Storage Used" | cut -d: -f2 | tr -d ' ')
|
|
|
|
json_add_string "storage_path" "${storage:-/srv/backups}"
|
|
json_add_string "storage_used" "${used:-0}"
|
|
|
|
# Last backup times
|
|
json_add_object "last_backup"
|
|
for type in config containers services; do
|
|
local latest=$(ls -t "${storage:-/srv/backups}/$type/"*.tar* 2>/dev/null | head -1)
|
|
if [ -n "$latest" ]; then
|
|
local date=$(stat -c %Y "$latest" 2>/dev/null)
|
|
json_add_int "$type" "${date:-0}"
|
|
else
|
|
json_add_int "$type" 0
|
|
fi
|
|
done
|
|
json_close_object
|
|
|
|
# Container count
|
|
local containers=$(ls -d /srv/lxc/*/ 2>/dev/null | wc -l)
|
|
json_add_int "container_count" "$containers"
|
|
|
|
json_dump
|
|
;;
|
|
|
|
list)
|
|
json_load "$3"
|
|
json_get_var type type
|
|
type="${type:-all}"
|
|
|
|
local storage=$(uci -q get backup.main.storage_path)
|
|
storage="${storage:-/srv/backups}"
|
|
|
|
json_init
|
|
json_add_array "backups"
|
|
|
|
# List config backups
|
|
if [ "$type" = "all" ] || [ "$type" = "config" ]; then
|
|
for f in "$storage/config/"*.tar* 2>/dev/null; do
|
|
[ -f "$f" ] || continue
|
|
json_add_object ""
|
|
json_add_string "file" "$(basename "$f")"
|
|
json_add_string "type" "config"
|
|
json_add_string "size" "$(du -h "$f" 2>/dev/null | cut -f1)"
|
|
json_add_int "timestamp" "$(stat -c %Y "$f" 2>/dev/null)"
|
|
json_close_object
|
|
done
|
|
fi
|
|
|
|
# List container backups
|
|
if [ "$type" = "all" ] || [ "$type" = "containers" ]; then
|
|
for f in "$storage/containers/"*.tar* 2>/dev/null; do
|
|
[ -f "$f" ] || continue
|
|
json_add_object ""
|
|
json_add_string "file" "$(basename "$f")"
|
|
json_add_string "type" "container"
|
|
json_add_string "size" "$(du -h "$f" 2>/dev/null | cut -f1)"
|
|
json_add_int "timestamp" "$(stat -c %Y "$f" 2>/dev/null)"
|
|
json_close_object
|
|
done
|
|
fi
|
|
|
|
# List service backups
|
|
if [ "$type" = "all" ] || [ "$type" = "services" ]; then
|
|
for f in "$storage/services/"*.tar* 2>/dev/null; do
|
|
[ -f "$f" ] || continue
|
|
json_add_object ""
|
|
json_add_string "file" "$(basename "$f")"
|
|
json_add_string "type" "service"
|
|
json_add_string "size" "$(du -h "$f" 2>/dev/null | cut -f1)"
|
|
json_add_int "timestamp" "$(stat -c %Y "$f" 2>/dev/null)"
|
|
json_close_object
|
|
done
|
|
fi
|
|
|
|
json_close_array
|
|
json_dump
|
|
;;
|
|
|
|
container_list)
|
|
json_init
|
|
json_add_array "containers"
|
|
|
|
for dir in /srv/lxc/*/; do
|
|
[ -d "$dir" ] || continue
|
|
local name=$(basename "$dir")
|
|
[ -f "$dir/config" ] || continue
|
|
|
|
local state="stopped"
|
|
lxc-info -n "$name" 2>/dev/null | grep -q "RUNNING" && state="running"
|
|
local size=$(du -sh "$dir" 2>/dev/null | awk '{print $1}')
|
|
|
|
# Count backups for this container
|
|
local storage=$(uci -q get backup.main.storage_path)
|
|
storage="${storage:-/srv/backups}"
|
|
local backup_count=$(ls -1 "$storage/containers/${name}-"*.tar* 2>/dev/null | wc -l)
|
|
|
|
json_add_object ""
|
|
json_add_string "name" "$name"
|
|
json_add_string "state" "$state"
|
|
json_add_string "size" "$size"
|
|
json_add_int "backups" "$backup_count"
|
|
json_close_object
|
|
done
|
|
|
|
json_close_array
|
|
json_dump
|
|
;;
|
|
|
|
create)
|
|
json_load "$3"
|
|
json_get_var type type
|
|
type="${type:-full}"
|
|
|
|
local result
|
|
result=$($BACKUP_CMD create --$type 2>&1)
|
|
local rc=$?
|
|
|
|
json_init
|
|
json_add_int "code" "$rc"
|
|
json_add_string "output" "$result"
|
|
json_dump
|
|
;;
|
|
|
|
restore)
|
|
json_load "$3"
|
|
json_get_var file file
|
|
json_get_var dry_run dry_run
|
|
|
|
[ -z "$file" ] && {
|
|
json_init
|
|
json_add_int "code" 1
|
|
json_add_string "error" "No file specified"
|
|
json_dump
|
|
exit 0
|
|
}
|
|
|
|
local opts=""
|
|
[ "$dry_run" = "1" ] || [ "$dry_run" = "true" ] && opts="--dry-run"
|
|
|
|
local result
|
|
result=$($BACKUP_CMD restore "$file" $opts 2>&1)
|
|
local rc=$?
|
|
|
|
json_init
|
|
json_add_int "code" "$rc"
|
|
json_add_string "output" "$result"
|
|
json_dump
|
|
;;
|
|
|
|
cleanup)
|
|
local result
|
|
result=$($BACKUP_CMD cleanup 2>&1)
|
|
local rc=$?
|
|
|
|
json_init
|
|
json_add_int "code" "$rc"
|
|
json_add_string "output" "$result"
|
|
json_dump
|
|
;;
|
|
|
|
container_backup)
|
|
json_load "$3"
|
|
json_get_var name name
|
|
|
|
[ -z "$name" ] && {
|
|
json_init
|
|
json_add_int "code" 1
|
|
json_add_string "error" "No container name specified"
|
|
json_dump
|
|
exit 0
|
|
}
|
|
|
|
local result
|
|
result=$($BACKUP_CMD container backup "$name" 2>&1)
|
|
local rc=$?
|
|
|
|
json_init
|
|
json_add_int "code" "$rc"
|
|
json_add_string "output" "$result"
|
|
json_dump
|
|
;;
|
|
|
|
container_restore)
|
|
json_load "$3"
|
|
json_get_var name name
|
|
json_get_var file file
|
|
|
|
[ -z "$name" ] || [ -z "$file" ] && {
|
|
json_init
|
|
json_add_int "code" 1
|
|
json_add_string "error" "Container name and backup file required"
|
|
json_dump
|
|
exit 0
|
|
}
|
|
|
|
local result
|
|
result=$($BACKUP_CMD container restore "$name" "$file" 2>&1)
|
|
local rc=$?
|
|
|
|
json_init
|
|
json_add_int "code" "$rc"
|
|
json_add_string "output" "$result"
|
|
json_dump
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
exit 0
|