Add per-workload capture of host-bind data volumes as downloadable tar.gz archives: a new internal/volsnap engine (enumerate host-bind volumes via the computeMounts merge, archive with archive/tar+gzip skipping symlinks/special files, per-workload retention + startup orphan cleanup), a volume_snapshots table + store CRUD, admin-gated API (list/snapshotable/create/download/delete), and a Snapshots panel on /apps/[id] that shows coverage and which volumes are skipped (and why). Scope: image-source apps, host-bind scopes (absolute/stage/project); Docker named volumes, tmpfs, and instance scope are surfaced as not-yet-supported. Restore is a separate later phase. Download/FilePath are containment-checked; create returns a typed no-data error (400) vs generic 500. Covered by archiver unit tests + full API e2e.
This commit is contained in:
@@ -91,6 +91,21 @@ type Backup struct {
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// VolumeSnapshot is one captured archive of a workload's host-bind data
|
||||
// volumes. Unlike Backup (global, SQLite-specific) it is per-workload and the
|
||||
// archive is a tar.gz of the resolved volume directories. Manifest is a
|
||||
// JSON-encoded []SnapshotVolume describing what the archive covers, so a
|
||||
// future restore can re-resolve each target even if volume settings drift.
|
||||
type VolumeSnapshot struct {
|
||||
ID string `json:"id"`
|
||||
WorkloadID string `json:"workload_id"`
|
||||
Label string `json:"label"`
|
||||
Filename string `json:"filename"`
|
||||
SizeBytes int64 `json:"size_bytes"`
|
||||
Manifest string `json:"manifest"` // JSON []SnapshotVolume
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// DNSRecord tracks a DNS record managed by the application.
|
||||
type DNSRecord struct {
|
||||
ID string `json:"id"`
|
||||
@@ -164,11 +179,11 @@ type WorkloadEnv struct {
|
||||
// by image cfg.Env and workload_env).
|
||||
type SharedSecret struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"` // the env KEY
|
||||
Value string `json:"value"` // ciphertext when Encrypted; never returned decrypted by the API
|
||||
Name string `json:"name"` // the env KEY
|
||||
Value string `json:"value"` // ciphertext when Encrypted; never returned decrypted by the API
|
||||
Encrypted bool `json:"encrypted"`
|
||||
Scope string `json:"scope"` // global | app
|
||||
AppID string `json:"app_id"` // set when scope == app; "" for global
|
||||
Scope string `json:"scope"` // global | app
|
||||
AppID string `json:"app_id"` // set when scope == app; "" for global
|
||||
Description string `json:"description"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
|
||||
Reference in New Issue
Block a user