package restore import ( "context" "fmt" "os" "strings" "gitea.hsrv.site/mrleo1nid/backup-master/internal/sysx" ) const ( agentConfigPath = "/etc/backup-agent/agent.yaml" agentService = `[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 ` agentTimer = `[Unit] Description=Ежедневный бэкап backup-master [Timer] OnCalendar=*-*-* 03:00:00 RandomizedDelaySec=30m Persistent=true [Install] WantedBy=timers.target ` ) // Takeover — делать ли восстановленный сервер основным для бэкапов. const ( TakeoverAsk = "" TakeoverYes = "yes" TakeoverNo = "no" ) // takeover переводит бэкапы клиента на этот сервер: сервер бэкапов выпускает новый // токен (старый отзывается — агент старого сервера получит отказ) и здесь ставится агент. func (r *restorer) takeover() { mode := r.opts.Takeover if mode == TakeoverAsk { mode = TakeoverNo if r.opts.Yes || confirmDefaultYes("Сделать этот сервер основным для бэкапов? Агент старого сервера перестанет их присылать") { mode = TakeoverYes } } step("Бэкапы этого сервера") if mode != TakeoverYes { info("агент не установлен — бэкапы по-прежнему присылает старый сервер (пробное восстановление)") r.todo = append(r.todo, "Чтобы этот сервер стал основным: в карточке клиента «Новый токен агента» и выполнить выданную команду здесь") return } token, err := r.client.Takeover(r.ctx) if err != nil { r.warn("не удалось перевести бэкапы на этот сервер: %v — установите агента вручную (карточка клиента → «Новый токен агента»)", err) return } if err := installAgent(r.ctx, r.opts.Server, token); err != nil { r.warn("агент не установлен: %v — токен уже перевыпущен, установите агента вручную (карточка клиента → «Новый токен агента»)", err) return } info("агент установлен, бэкапы теперь присылает этот сервер; токен старого сервера отозван") r.todo = append(r.todo, "Старый сервер больше не может слать бэкапы (токен отозван). При выводе из работы: sudo systemctl disable --now backup-agent.timer", "Первый бэкап с нового сервера сразу: sudo systemctl start backup-agent") } func installAgent(ctx context.Context, server, token string) error { if err := os.MkdirAll("/etc/backup-agent", 0o700); err != nil { return err } cfg := fmt.Sprintf("server: %s\ntoken: %s\nspool_dir: /var/tmp/backup-agent\n", strings.TrimRight(server, "/"), token) if err := os.WriteFile(agentConfigPath, []byte(cfg), 0o600); err != nil { return err } for path, body := range map[string]string{ "/etc/systemd/system/backup-agent.service": agentService, "/etc/systemd/system/backup-agent.timer": agentTimer, } { if err := os.WriteFile(path, []byte(body), 0o644); err != nil { return err } } if err := sysx.Run(ctx, "systemctl", "daemon-reload"); err != nil { return err } return sysx.Run(ctx, "systemctl", "enable", "--now", "backup-agent.timer") }