package server import ( "crypto/sha256" "encoding/hex" "io" "net/http" "os" "path/filepath" "regexp" "runtime" "strings" "text/template" "time" ) var agentScript = template.Must(template.New("agent.sh").Parse(`#!/usr/bin/env bash # Установка/обновление агента backup-master. # curl -fsSL {{.URL}}/agent.sh | sudo bash -s -- --token <токен> [--now] # Без --token обновляет бинарник и юниты, сохраняя существующий конфиг. set -Eeuo pipefail SERVER="{{.URL}}" TOKEN="" RUN_NOW=n while [[ $# -gt 0 ]]; do case $1 in --token) TOKEN=$2; shift 2 ;; --now) RUN_NOW=y; shift ;; *) echo "Неизвестный аргумент: $1" >&2; exit 1 ;; esac done [[ $EUID -eq 0 ]] || { echo "Запустите от root (sudo)" >&2; exit 1; } case $(uname -m) in x86_64) ARCH=amd64 ;; aarch64|arm64) ARCH=arm64 ;; *) echo "Архитектура $(uname -m) не поддерживается" >&2; exit 1 ;; esac CONF=/etc/backup-agent/agent.yaml if [[ -z $TOKEN && ! -f $CONF ]]; then echo "Нужен --token (выдаётся в веб-морде при добавлении клиента)" >&2; exit 1 fi echo "==> Скачиваю backupctl ($ARCH)" curl -fsSL "$SERVER/dl/backupctl-linux-$ARCH" -o /usr/local/bin/backupctl.new chmod 755 /usr/local/bin/backupctl.new mv -f /usr/local/bin/backupctl.new /usr/local/bin/backupctl /usr/local/bin/backupctl version if [[ -n $TOKEN ]]; then echo "==> Конфиг $CONF" install -d -m 700 /etc/backup-agent umask 077 cat >"$CONF" < systemd-юниты" cat >/etc/systemd/system/backup-agent.service <<'EOF' [Unit] Description=backup-master agent Wants=network-online.target After=network-online.target docker.service [Service] Type=oneshot ExecStart=/usr/local/bin/backupctl backup Nice=10 IOSchedulingClass=idle TimeoutStartSec=6h EOF cat >/etc/systemd/system/backup-agent.timer <<'EOF' [Unit] Description=Ежедневный бэкап backup-master [Timer] OnCalendar=*-*-* 03:00:00 RandomizedDelaySec=30m Persistent=true [Install] WantedBy=timers.target EOF systemctl daemon-reload systemctl enable --now backup-agent.timer echo "==> Что будет в бэкапе" /usr/local/bin/backupctl plan || true if [[ $RUN_NOW == y ]]; then echo "==> Первый бэкап (журнал: journalctl -u backup-agent -f)" systemctl start --no-block backup-agent.service fi echo "Готово. Расписание: systemctl list-timers backup-agent.timer" `)) var restoreScript = template.Must(template.New("restore.sh").Parse(`#!/usr/bin/env bash # Восстановление сервера из backup-master. # curl -fsSL {{.URL}}/restore.sh | sudo bash -s -- --token [--backup ID] [--skip-heavy] [--skip-provision] set -Eeuo pipefail SERVER="{{.URL}}" [[ $EUID -eq 0 ]] || { echo "Запустите от root (sudo)" >&2; exit 1; } case $(uname -m) in x86_64) ARCH=amd64 ;; aarch64|arm64) ARCH=arm64 ;; *) echo "Архитектура $(uname -m) не поддерживается" >&2; exit 1 ;; esac command -v curl >/dev/null || { apt-get update -q && apt-get install -y -q curl; } echo "==> Скачиваю backupctl ($ARCH)" curl -fsSL "$SERVER/dl/backupctl-linux-$ARCH" -o /usr/local/bin/backupctl.new chmod 755 /usr/local/bin/backupctl.new mv -f /usr/local/bin/backupctl.new /usr/local/bin/backupctl # stdin занят пайпом curl — вопросы задаём через терминал if [[ -r /dev/tty ]]; then exec /usr/local/bin/backupctl restore --server "$SERVER" "$@"