feat(samba): lifecycle — ensureSamba/ReconcileSamba/password/disable (R-7 slice 1, Part 2)
ensureSamba joins EnsureBaseStack after filebrowser, gated on SMB.Enabled (cloudflared conditional precedent); reconcile is idempotent (unchanged config + running container = ZERO compose calls, asserted via seam). Atomic tmp+fsync+ rename config writes. Password applied via smbpasswd on STDIN (never argv/log/ settings). Disable = compose down, volumes + folders KEPT. samba added to IsProtectedStack in code (controller.yaml is golden-generated and predates it), which also makes the app-backup loops correctly skip it.
This commit is contained in:
@@ -396,8 +396,22 @@ func validate(cfg *Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsProtectedStack checks if a stack name is in the protected list.
|
||||
// alwaysProtectedStacks are controller-MANAGED infra stacks that are protected regardless of the
|
||||
// configured list. cfg.Stacks.Protected comes from controller.yaml (golden/bootstrap-generated) and
|
||||
// predates these, so a box whose controller.yaml has not been regenerated would otherwise expose
|
||||
// them as ordinary, stoppable/deletable apps. Protection means: no stop/delete from the UI, and the
|
||||
// app-backup loops skip them (they are infrastructure, not customer apps — samba's share data is
|
||||
// classified through its own registry instead, see stacks.ClassifiedBinds).
|
||||
var alwaysProtectedStacks = map[string]bool{
|
||||
"samba": true, // LAN network-sharing infra stack (R-7)
|
||||
}
|
||||
|
||||
// IsProtectedStack checks if a stack name is protected — either controller-managed infra (always)
|
||||
// or listed in the configured protected list.
|
||||
func (cfg *Config) IsProtectedStack(name string) bool {
|
||||
if alwaysProtectedStacks[strings.ToLower(name)] {
|
||||
return true
|
||||
}
|
||||
for _, p := range cfg.Stacks.Protected {
|
||||
if strings.EqualFold(p, name) {
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user