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:
2026-06-15 19:26:02 +02:00
parent bc41acf4da
commit 42f69dadda
10 changed files with 293 additions and 46 deletions
+20
View File
@@ -39,6 +39,11 @@ type Settings struct {
// Cross-drive restic repo password (auto-generated on first use)
CrossDriveResticPassword string `json:"cross_drive_restic_password,omitempty"`
// Last-seen guest boot-id (intermediary-mount model): persisted so the controller can detect a guest
// reboot across its own restart (it restarts with the guest) and deterministically recreate
// drive-backed apps once the agent re-propagates the drive.
LastGuestBootID string `json:"last_guest_boot_id,omitempty"`
// Hub verification state
HubVerified bool `json:"hub_verified,omitempty"`
HubVerifiedAt string `json:"hub_verified_at,omitempty"` // RFC3339
@@ -931,6 +936,21 @@ func (s *Settings) SetHubVerified(verified bool, at time.Time) error {
}
// SetHubLastCheck updates the last Hub check timestamp without changing verification status.
// GetLastGuestBootID returns the persisted last-seen guest boot-id ("" if never recorded).
func (s *Settings) GetLastGuestBootID() string {
s.mu.RLock()
defer s.mu.RUnlock()
return s.LastGuestBootID
}
// SetLastGuestBootID persists the current guest boot-id (after a deterministic boot-recreate pass).
func (s *Settings) SetLastGuestBootID(id string) error {
s.mu.Lock()
defer s.mu.Unlock()
s.LastGuestBootID = id
return s.save()
}
func (s *Settings) SetHubLastCheck(at time.Time) error {
s.mu.Lock()
defer s.mu.Unlock()