// 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"` // абсолютные пути в /files/ Binaries []string `json:"binaries,omitempty"` // абсолютные пути в /bin/ (fallback) Dumps []Dump `json:"dumps,omitempty"` Volumes []Volume `json:"volumes,omitempty"` Heavy []string `json:"heavy,omitempty"` // пути, ушедшие в отдельную часть 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 — файл в /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-том, содержимое в /volumes//. 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"