controller v0.68.0: storage lifecycle on intermediary model (H2/H3/M1/M3 + boot-id)
H2 decommission UI button (migrate / anyway); H3 one-click re-enroll of a
decommissioned drive; M1 default reassignment (auto-promote + block-if-none);
M3 migrate re-asserts 2775 setgid on userdata dirs; deterministic guest-reboot
recreate via agent boot_id (replaces the timed sample). Fixes the {path}/{where}
H1 JS bug. Non-hollow tests + companions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -851,9 +851,12 @@ func walkMerge(lg *log.Logger, srcNS, dstNS string, skip map[string]bool, assert
|
||||
if err := os.MkdirAll(dst, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
// #8 (v0.66.0): preserve the SOURCE dir's full mode (incl. setgid) + group, so the userdata
|
||||
// ownership convention (2775 setgid, gid 1000) survives a whole-drive migration. MkdirAll's
|
||||
// mode is umask-masked + drops setgid, so re-stamp explicitly from the source.
|
||||
// M3: userdata dirs ALWAYS get the 2775-setgid/gid-1000 convention RE-ASSERTED (not merely
|
||||
// source-preserved), so a PRE-EXISTING stale 755 target dir is corrected regardless of the
|
||||
// source mode. Other dirs keep #8's source-mode preservation.
|
||||
if isUserdataDir(rel) {
|
||||
return appbackup.EnsureUserdataDir(dst)
|
||||
}
|
||||
return preserveDirOwnership(dst, d)
|
||||
}
|
||||
|
||||
@@ -1018,6 +1021,14 @@ func copyFile(src, dst string) (int64, error) {
|
||||
|
||||
// preserveDirOwnership re-stamps a freshly-created target dir with the SOURCE dir's full mode (incl.
|
||||
// setgid) and group — part of the #8 fix so the userdata convention survives a migration.
|
||||
// isUserdataDir reports whether a namespace-relative path is the userdata tree (the customer-facing
|
||||
// shared-content area) — `userdata` itself or anything under it — which must carry the 2775-setgid
|
||||
// convention. Normalised to forward slashes so it matches on any host.
|
||||
func isUserdataDir(rel string) bool {
|
||||
r := filepath.ToSlash(rel)
|
||||
return r == "userdata" || strings.HasPrefix(r, "userdata/")
|
||||
}
|
||||
|
||||
func preserveDirOwnership(dst string, d fs.DirEntry) error {
|
||||
info, err := d.Info()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user