feat(borg): Layer 2 panel integration (module + two GUIs + hooks + installers)
Native ApisCP integration, adapted from apiscp-kopia's Layer 2 against the real borg Layer 1 subcommands: - Borg_Module_Surrogate: admin + PRIVILEGE_SITE verbs, sudo boundary, config whitelist (now enforced), site-owner verbs derive the site from the auth context only, ownsDatabase gate, confirm-guarded destructive import. - Admin GUI (apps/borg, "Borg Backups"): repository (BORG_REPO/passphrase/ encryption/RSH, check-access, init, one-time recovery-key panel + download + irrecoverable tick), backup selection, retention + excludes + prune-now, schedule, maintenance (compact) + verify (check), notifications, tabbed layout, running overlay, double-submit guard, consolidated Restore workflow. - Site-owner GUI (apps/myborgbackups, "My Borg Backups"): restore files / whole account / databases, run own backup, scoped to the caller's own site. - Account hooks, install-layer2.sh, uninstall.sh (safe default, --purge). Borg differences vs kopia are handled: no backend types/sftp/server, no browse/ subpath or point-in-time (restores newest archive; archive dates shown for info), retention via config + `borg prune` (no global policy), import-db takes no dumpfile. All PHP lints clean; controller verb calls all resolve to the module.
This commit is contained in:
parent
3ce5bf1a47
commit
02403b72c0
14 changed files with 2681 additions and 0 deletions
114
uninstall.sh
Normal file
114
uninstall.sh
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# uninstall.sh: remove apiscp-borg (Layer 1 engine + Layer 2 panel integration).
|
||||
#
|
||||
# What it ALWAYS removes:
|
||||
# - the systemd timer/service (disabled + stopped first) and any schedule drop-in
|
||||
# - the Layer 1 binaries and shared library
|
||||
# - the Layer 2 module, both GUI apps, our menu links, account hooks, and the
|
||||
# scoped sudoers file
|
||||
# - the Prometheus textfile metric
|
||||
#
|
||||
# What it KEEPS by default (so an uninstall never destroys your ability to
|
||||
# recover): the Borg repository and all its archives (never touched), the borg
|
||||
# binary itself, /etc/apiscp-borg/config (holds the repository passphrase),
|
||||
# the staging dir, and the key backup dir.
|
||||
#
|
||||
# Pass --purge to ALSO delete /etc/apiscp-borg (config + passphrase!), the
|
||||
# staging dir (/var/lib/apiscp-borg), and the key backup dir. The Borg
|
||||
# repository and its archives are STILL not touched; remove those yourself with
|
||||
# borg if you really want the backups gone.
|
||||
#
|
||||
# Run as root on the ApisCP host. Idempotent.
|
||||
|
||||
set -u
|
||||
|
||||
PURGE=0
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--purge) PURGE=1 ;;
|
||||
-h|--help) sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
|
||||
*) echo "unknown option: $arg" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[ "$(id -u)" = 0 ] || { echo "run as root" >&2; exit 1; }
|
||||
|
||||
LIBDIR=/usr/local/lib/apiscp-borg
|
||||
BINDIR=/usr/local/bin
|
||||
UNITDIR=/etc/systemd/system
|
||||
CFGDIR=/etc/apiscp-borg
|
||||
STAGE=/var/lib/apiscp-borg
|
||||
CP_ROOT="${CP_ROOT:-/usr/local/apnscp}"
|
||||
|
||||
echo "== Layer 2: ApisCP panel integration =="
|
||||
# Module.
|
||||
rm -f "$CP_ROOT/lib/modules/surrogates/borg.php" && echo "removed module surrogate" || true
|
||||
# GUI apps (both editions).
|
||||
rm -rf "$CP_ROOT/config/custom/apps/borg" "$CP_ROOT/config/custom/apps/myborgbackups" && echo "removed GUI apps" || true
|
||||
# Menu links: strip our create_link lines (and their marker comment); drop the
|
||||
# file only if it becomes effectively empty.
|
||||
for _tpl in admin site; do
|
||||
_f="$CP_ROOT/config/custom/templates/$_tpl.php"
|
||||
[ -f "$_f" ] || continue
|
||||
if grep -q "apps/borg\|apps/myborgbackups\|apiscp-borg" "$_f"; then
|
||||
_tmp=$(mktemp)
|
||||
# Drop our marker comments and any create_link referencing our apps.
|
||||
grep -v "apiscp-borg" "$_f" | grep -v "create_link(.*apps/borg" | grep -v "create_link(.*apps/myborgbackups" > "$_tmp"
|
||||
# If nothing but "<?php" and whitespace remains, remove the file entirely.
|
||||
if [ -z "$(grep -vE '^\s*(<\?php)?\s*$' "$_tmp")" ]; then
|
||||
rm -f "$_f"; echo "removed $_tpl.php menu (was ours only)"
|
||||
else
|
||||
install -m 0644 "$_tmp" "$_f"; echo "stripped our link from $_tpl.php"
|
||||
fi
|
||||
rm -f "$_tmp"
|
||||
fi
|
||||
done
|
||||
# Account hooks (only the ones that are ours).
|
||||
for _hook in addDomain suspendDomain deleteDomain; do
|
||||
_h="$CP_ROOT/config/custom/hooks/$_hook.sh"
|
||||
[ -f "$_h" ] && grep -q apiscp-borg "$_h" 2>/dev/null && { rm -f "$_h"; echo "removed hook $_hook.sh"; }
|
||||
done
|
||||
# Sudoers.
|
||||
rm -f /etc/sudoers.d/apiscp-borg && echo "removed sudoers drop-in" || true
|
||||
# Restart the panel so it forgets the app/menu.
|
||||
systemctl restart apnscp 2>/dev/null || echo " restart apnscp yourself to drop the menu entry" >&2
|
||||
|
||||
echo "== Layer 1: engine =="
|
||||
# Stop + disable + remove the timer/service and any schedule drop-in.
|
||||
systemctl disable --now borg-apiscp-backup.timer 2>/dev/null || true
|
||||
systemctl stop borg-apiscp-backup.service 2>/dev/null || true
|
||||
rm -f "$UNITDIR/borg-apiscp-backup.timer" "$UNITDIR/borg-apiscp-backup.service"
|
||||
rm -rf "$UNITDIR/borg-apiscp-backup.timer.d"
|
||||
systemctl daemon-reload 2>/dev/null || true
|
||||
echo "removed systemd units"
|
||||
# Binaries + library.
|
||||
rm -f "$BINDIR/borg-apiscp-backup" "$BINDIR/borg-apiscp-restore" "$BINDIR/borg-apiscp-repo"
|
||||
rm -rf "$LIBDIR"
|
||||
echo "removed binaries and library"
|
||||
# Prometheus metric, if any.
|
||||
for d in /var/lib/node_exporter/textfile_collector /var/lib/prometheus/node-exporter /var/lib/prometheus/node_exporter; do
|
||||
rm -f "$d/apiscp-borg.prom" 2>/dev/null || true
|
||||
done
|
||||
|
||||
if [ "$PURGE" = 1 ]; then
|
||||
echo "== purge: removing config, staging, and key backups =="
|
||||
# Read KEY_BACKUP_DIR from the config before deleting it.
|
||||
_keydir=/root/apiscp-borg-keys
|
||||
[ -r "$CFGDIR/config" ] && _keydir=$(sed -n "s/^[[:space:]]*KEY_BACKUP_DIR[[:space:]]*=[[:space:]]*['\"]\{0,1\}\([^'\"]*\)['\"]\{0,1\}.*/\1/p" "$CFGDIR/config" | head -1)
|
||||
[ -n "$_keydir" ] || _keydir=/root/apiscp-borg-keys
|
||||
rm -rf "$CFGDIR" "$STAGE"
|
||||
echo "removed $CFGDIR and $STAGE"
|
||||
echo "NOTE: the key backup dir ($_keydir) is your ONLY offline copy of the repository passphrase/key."
|
||||
echo " Remove it yourself if you are certain: rm -rf '$_keydir'"
|
||||
else
|
||||
echo "kept $CFGDIR (repository passphrase), $STAGE, and the key backup dir."
|
||||
echo "Re-run with --purge to remove them too."
|
||||
fi
|
||||
|
||||
cat <<'EOF'
|
||||
|
||||
Uninstalled. The Borg repository and all its archives were NOT touched: your
|
||||
backups are intact and can still be restored with plain borg, or by
|
||||
reinstalling apiscp-borg. borg itself was left installed.
|
||||
EOF
|
||||
Loading…
Add table
Add a link
Reference in a new issue