Агент: - ssh: sshd_config(.d), ключи хоста, authorized_keys root и пользователей - system: весь /etc/ufw и /etc/default/ufw, /etc/sysctl.conf, /etc/hosts, свои файлы в /etc/cron.d (пакетные отсекаются через dpkg -S) - certs: /etc/letsencrypt, /root/.acme.sh; xui: сертификаты по путям из базы - docker: daemon.json и логины в registry; telegraf: /etc/default/telegraf - caddy: бинарник бэкапится, если Caddy собран с плагинами - units: свои systemd-юниты с состоянием enabled/active и drop-in *.service.d - etc: изменённые конфиги любых пакетов (dpkg conffiles) и свои файлы в /etc, кроме привязанного к железу и облаку - в манифесте: часовой пояс, swap, вручную поставленные пакеты; версия apt-пакета в строке категории - предупреждения: программы юнитов вне бэкапа, каталоги /opt и /usr/local/bin без категории, контейнеры без compose Restore: - часовой пояс, swap-файл, доустановка вручную поставленных пакетов - свои юниты включаются и запускаются как на старом сервере Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
121 lines
5.5 KiB
Go
121 lines
5.5 KiB
Go
// Package manifest описывает метаданные бэкапа: что и откуда собрано, какие версии
|
|
// стояли на сервере. Манифест лежит первым файлом в main-архиве и отдельно хранится
|
|
// на сервере, чтобы restore мог спланировать восстановление до скачивания архива.
|
|
package manifest
|
|
|
|
import "time"
|
|
|
|
const FormatVersion = 1
|
|
|
|
// MainPart — имя основной части бэкапа. Остальные части — heavy-категории.
|
|
const MainPart = "main"
|
|
|
|
type Manifest struct {
|
|
FormatVersion int `json:"format_version"`
|
|
AgentVersion string `json:"agent_version"`
|
|
Domain string `json:"domain"`
|
|
Hostname string `json:"hostname"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
OS OSInfo `json:"os"`
|
|
Packages map[string]string `json:"packages,omitempty"` // apt-пакет → точная версия dpkg
|
|
Features Features `json:"features"`
|
|
SudoUsers []string `json:"sudo_users,omitempty"`
|
|
Timezone string `json:"timezone,omitempty"`
|
|
Swap []SwapFile `json:"swap,omitempty"`
|
|
// ManualPackages — пакеты, поставленные вручную (apt-mark showmanual): restore доставит недостающие.
|
|
ManualPackages []string `json:"manual_packages,omitempty"`
|
|
Categories []Category `json:"categories"`
|
|
Parts []string `json:"parts"` // main + heavy-части, вошедшие в этот бэкап
|
|
Warnings []string `json:"warnings,omitempty"`
|
|
}
|
|
|
|
type OSInfo struct {
|
|
ID string `json:"id"`
|
|
VersionID string `json:"version_id"`
|
|
PrettyName string `json:"pretty_name"`
|
|
Arch string `json:"arch"` // как dpkg --print-architecture: amd64, arm64
|
|
}
|
|
|
|
// Features — признаки базовой настройки vps_installer, которые нужно повторить.
|
|
type Features struct {
|
|
Blocklist bool `json:"blocklist"`
|
|
SSHHardened bool `json:"ssh_hardened"`
|
|
}
|
|
|
|
type Category struct {
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Auto bool `json:"auto,omitempty"` // найдена автоматически, в каталоге не описана
|
|
Version string `json:"version,omitempty"`
|
|
Install string `json:"install,omitempty"` // recipe установки бинарника
|
|
Service *ServiceState `json:"service,omitempty"`
|
|
Units []ServiceState `json:"units,omitempty"` // тип units: свои systemd-юниты и их состояние
|
|
Paths []string `json:"paths,omitempty"` // абсолютные пути в <cat>/files/
|
|
Binaries []string `json:"binaries,omitempty"` // абсолютные пути в <cat>/bin/ (fallback)
|
|
Dumps []Dump `json:"dumps,omitempty"`
|
|
Volumes []Volume `json:"volumes,omitempty"`
|
|
Heavy []string `json:"heavy,omitempty"` // пути, ушедшие в отдельную часть <cat>
|
|
HeavySkipped bool `json:"heavy_skipped,omitempty"`
|
|
Compose *Compose `json:"compose,omitempty"`
|
|
EnsureDirs []string `json:"ensure_dirs,omitempty"`
|
|
PostRestore []string `json:"post_restore,omitempty"`
|
|
RestoreAfter []string `json:"restore_after,omitempty"`
|
|
}
|
|
|
|
type SwapFile struct {
|
|
Path string `json:"path"`
|
|
Size int64 `json:"size"` // байт
|
|
}
|
|
|
|
type ServiceState struct {
|
|
Unit string `json:"unit"`
|
|
Enabled bool `json:"enabled"`
|
|
Active bool `json:"active"`
|
|
}
|
|
|
|
// Dump — файл в <cat>/dumps/. Kind: postgres, mongo, mysql, mariadb, sqlite, cmd.
|
|
type Dump struct {
|
|
Name string `json:"name"`
|
|
Kind string `json:"kind"`
|
|
Service string `json:"service,omitempty"` // compose-сервис
|
|
Target string `json:"target,omitempty"` // sqlite: куда положить файл при восстановлении
|
|
RestoreCmd string `json:"restore_cmd,omitempty"` // cmd: команда, получает DUMP_FILE
|
|
}
|
|
|
|
// Volume — именованный docker-том, содержимое в <cat>/volumes/<name>/.
|
|
type Volume struct {
|
|
Name string `json:"name"` // реальное имя тома в docker
|
|
Key string `json:"key"` // ключ в compose-файле
|
|
}
|
|
|
|
type Compose struct {
|
|
Project string `json:"project"`
|
|
Dir string `json:"dir"`
|
|
ConfigFiles []string `json:"config_files"` // абсолютные пути
|
|
Running bool `json:"running"`
|
|
Images map[string]Image `json:"images,omitempty"` // по имени сервиса
|
|
ExternalNetworks []string `json:"external_networks,omitempty"`
|
|
Git *GitInfo `json:"git,omitempty"`
|
|
}
|
|
|
|
type Image struct {
|
|
Ref string `json:"ref"`
|
|
Digest string `json:"digest,omitempty"` // repo@sha256:...
|
|
Built bool `json:"built,omitempty"`
|
|
}
|
|
|
|
type GitInfo struct {
|
|
Remote string `json:"remote,omitempty"`
|
|
Commit string `json:"commit"`
|
|
Dirty bool `json:"dirty,omitempty"`
|
|
}
|
|
|
|
// Archive-пути внутри tar.
|
|
|
|
func FilesPrefix(cat string) string { return cat + "/files/" }
|
|
func BinPrefix(cat string) string { return cat + "/bin/" }
|
|
func DumpsPrefix(cat string) string { return cat + "/dumps/" }
|
|
func VolumesPrefix(cat string) string { return cat + "/volumes/" }
|
|
|
|
const ManifestFile = "manifest.json"
|