Агенты подхватывают изменения с сервера: каталог и самообновление
CI / test (push) Successful in 1m29s

- сервер отдаёт агенту итоговый каталог (встроенный каталог сервера +
  переопределения клиента); если каталог не подходит версии агента —
  встроенный каталог агента и предупреждение
- самообновление перед бэкапом: версия сервера новее → скачивание с того же
  сервера (только /dl/...), проверка sha256 и запуска новой версии, подмена
  с откатом, перезапуск через exec; при ошибке бэкап идёт текущей версией
- галочка «Автообновление» у клиента (по умолчанию включена), версия агента
  в списке и карточке, отставшие подсвечены; версия сервера в шапке
- миграция существующей базы: колонки auto_update и agent_version
- backupctl backup --no-update

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mrleo1nidandClaude Opus 5.5 committed 2026-10-17 15:27:31 +03:00
1 parent 1947b26913
commit 488abc2d34
21 files changed
+674 -51

No files matched your search

+6 -1
View File
@@ -16,6 +16,7 @@ import (
"gitea.hsrv.site/mrleo1nid/backup-master/internal/catalog"
"gitea.hsrv.site/mrleo1nid/backup-master/internal/manifest"
"gitea.hsrv.site/mrleo1nid/backup-master/internal/version"
)
//go:embed templates/*.html
@@ -95,6 +96,7 @@ func (s *Server) render(w http.ResponseWriter, r *http.Request, page string, dat
data["CSRF"] = csrfFrom(r)
data["Page"] = page
data["PublicURL"] = s.cfg.PublicURL
data["ServerVersion"] = s.cfg.Version
var buf bytes.Buffer
if err := t.Execute(&buf, data); err != nil {
log.Printf("render %s: %v", page, err)
@@ -127,6 +129,7 @@ type clientRow struct {
*Client
StatusClass, StatusText string
LastSize int64
Outdated bool // агент старее сервера
}
func (s *Server) webClientNew(w http.ResponseWriter, r *http.Request) {
@@ -196,7 +199,8 @@ func (s *Server) renderClient(w http.ResponseWriter, r *http.Request, c *Client,
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
data := map[string]any{"Client": c, "Backups": backups, "Error": formErr}
data := map[string]any{"Client": c, "Backups": backups, "Error": formErr,
"AgentOutdated": c.AgentVersion != "" && version.ShouldUpdate(s.cfg.Version, c.AgentVersion)}
data["StatusClass"], data["StatusText"] = clientStatus(c)
if latest, err := s.st.LatestComplete(c.ID); err == nil {
var m manifest.Manifest
@@ -230,6 +234,7 @@ func (s *Server) webClientSettings(w http.ResponseWriter, r *http.Request) {
c.HeavyEveryDays = formInt(r, "heavy_every_days", c.HeavyEveryDays)
c.StaleHours = formInt(r, "stale_hours", c.StaleHours)
c.Disabled = r.FormValue("disabled") == "1"
c.AutoUpdate = r.FormValue("auto_update") == "1"
if strings.TrimSpace(c.ConfigYAML) != "" {
base, err := catalog.Default()
if err == nil {