Files
felhom-controller/controller/internal/stacks/samba_classify.go
T
admin 3b70a9e9ab docs(shares): R-7b v0.145.0 — CHANGELOG, CONTEXT, REUSE, README; caveats cleared
The samba_classify.go SCOPE NOTE and the README KNOWN GAP both described a gap that
R-7b closes; both now describe the sibling-shares-source execution instead.
2026-07-18 13:06:41 +02:00

71 lines
2.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package stacks
import (
"path/filepath"
"strings"
"gitea.dooplex.hu/admin/felhom-controller/internal/appbackup"
)
// Backup classification for the samba stack (R-7 slice 1, [R4]).
//
// samba is CONTROLLER-GENERATED infra: it has no .felhom.yml and its compose binds are absolute
// share paths, so the catalog path (LoadMetadata → ParseComposeClassifiableBinds → ClassifyBinds)
// cannot classify it. Its classification comes from the SHARES REGISTRY instead:
//
// share.Offsite == true → ClassMandatory → TierOffsite (offsite) AND TierSecondary (tier-2)
// share.Offsite == false → ClassOptional → TierSecondary only (never offsite)
//
// The smb.conf / passdb mounts are deliberately NOT emitted — they are config, not customer data.
//
// EXECUTION (R-7b, v0.145.0 — the gap this note used to describe is CLOSED). Share data now reaches
// BOTH live tiers, but not through this seam: the engines remain structured around a per-app recovery
// unit (backup.RunTier2 still short-circuits on `os.Stat(unitDir)`; the offsite runner still
// enumerates settings.GetOffboxApps()), and Model B deliberately left those paths byte-identical.
// Instead the backup package runs a SIBLING shares source off the SAME registry this file reads —
// backup.RunSharesTier2 and backup.runOffboxSharesLeg — applying the identical rule below.
//
// So this function and the shares sources agree by construction on WHAT each share's class is, while
// the sources own WHERE it goes. Keep the rule here in sync with internal/backup/shares_payload.go's
// classifiedShares if it ever changes.
func (m *Manager) sambaClassifiedBinds() ([]appbackup.ClassifiedBind, bool) {
if m.settings == nil {
return nil, false
}
shares := m.settings.GetSMBShares()
out := make([]appbackup.ClassifiedBind, 0, len(shares))
for _, sh := range shares {
cls := appbackup.ClassOptional
if sh.Offsite {
cls = appbackup.ClassMandatory
}
out = append(out, appbackup.ClassifiedBind{
ComposeBind: appbackup.ComposeBind{
Root: appbackup.RootHDD,
RelPath: m.shareRelPath(sh.Path),
ReadOnly: sh.ReadOnly,
},
Class: cls,
Origin: appbackup.OriginExplicit, // the customer's per-share Felhőmentés toggle IS explicit
})
}
return out, true
}
// shareRelPath expresses a share's absolute path relative to its owning registered storage root, so
// the emitted bind matches the (Root, RelPath) + root-path resolution shape the capture-set helpers
// use. A share under no registered root falls back to the path minus its leading slash (never
// absolute — the structural guards reject absolute RelPaths).
func (m *Manager) shareRelPath(path string) string {
p := filepath.ToSlash(path)
if m.settings != nil {
for _, sp := range m.settings.GetStoragePaths() {
root := filepath.ToSlash(sp.Path)
if strings.HasPrefix(p, root+"/") {
return strings.TrimPrefix(p, root+"/")
}
}
}
return strings.TrimPrefix(p, "/")
}