controller v0.67.0: intermediary-mount — HDD_PATH repoint + drive-absent gate + H1 routes
Drives are visible in-guest only at the STABLE /mnt/felhom-drives/<name>; the registered path + HDD_PATH + FileBrowser source repoint there while agent calls map back to raw /mnt/<name> (agentWhere). Enroll binds-under-parent before register. Drive-absent GATE (planDriveGates + 30s driveGateLoop) stops/blocks apps when a drive vanishes and auto-restarts on return; start-gate refuses start when the drive is absent. H1 endpoints (disconnect/reconnect/restart-apps) routed onto host-side ops. Non-hollow tests + companions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -116,15 +116,19 @@ func (s *Server) runStorageInit(ctx context.Context, agent diskAgent, device, fs
|
||||
if uuid == "" {
|
||||
return storageInitResult{}, fmt.Errorf("formázás kész, de az új fájlrendszer-azonosító nem feloldható — frissítsen és használja a Csatolás funkciót")
|
||||
}
|
||||
// 3. Mount (benign assign) + 4. register.
|
||||
// 3. Mount (benign assign) at the raw /mnt/<name>. 4. Bind felhom-data under the shared parent FIRST
|
||||
// (intermediary model) so the drive's STABLE path is live in the guest, THEN register + skeleton there
|
||||
// (the controller can only see/write the drive at the stable path post-attach). 5. Register the stable
|
||||
// path — that is what apps' HDD_PATH / FileBrowser / monitoring use.
|
||||
if err := agent.AssignDisk(ctx, uuid, where, fstype, ""); err != nil {
|
||||
return storageInitResult{}, fmt.Errorf("csatlakoztatás sikertelen: %w", err)
|
||||
}
|
||||
if err := s.registerStoragePath(where, label, setDefault); err != nil {
|
||||
s.attachIntoGuest(ctx, agent, where)
|
||||
stable := stablePathForName(path.Base(where))
|
||||
if err := s.registerStoragePath(stable, label, setDefault); err != nil {
|
||||
return storageInitResult{}, err
|
||||
}
|
||||
s.attachIntoGuest(ctx, agent, where)
|
||||
return storageInitResult{Registered: true, Where: where}, nil
|
||||
return storageInitResult{Registered: true, Where: stable}, nil
|
||||
}
|
||||
|
||||
// attachIntoGuest passes an enrolled drive INTO the guest (slice 10 P2) so the controller + apps can
|
||||
@@ -152,11 +156,12 @@ func (s *Server) runStorageAttach(ctx context.Context, agent diskAgent, device,
|
||||
if err := agent.AssignDisk(ctx, uuid, where, fstype, ""); err != nil {
|
||||
return storageInitResult{}, fmt.Errorf("csatlakoztatás sikertelen: %w", err)
|
||||
}
|
||||
if err := s.registerStoragePath(where, label, setDefault); err != nil {
|
||||
s.attachIntoGuest(ctx, agent, where)
|
||||
stable := stablePathForName(path.Base(where))
|
||||
if err := s.registerStoragePath(stable, label, setDefault); err != nil {
|
||||
return storageInitResult{}, err
|
||||
}
|
||||
s.attachIntoGuest(ctx, agent, where)
|
||||
return storageInitResult{Registered: true, Where: where}, nil
|
||||
return storageInitResult{Registered: true, Where: stable}, nil
|
||||
}
|
||||
|
||||
// pendingActivationDrives returns registered storage paths that are NOT yet live-mounted in this
|
||||
@@ -288,6 +293,12 @@ func (s *Server) ServeStorageAPI(w http.ResponseWriter, r *http.Request) {
|
||||
s.handleStorageMigrateStatus(w, r)
|
||||
case r.URL.Path == "/api/storage/decommission" && r.Method == http.MethodPost:
|
||||
s.handleStorageDecommission(w, r)
|
||||
case r.URL.Path == "/api/storage/disconnect" && r.Method == http.MethodPost:
|
||||
s.handleStorageDisconnect(w, r)
|
||||
case r.URL.Path == "/api/storage/reconnect" && r.Method == http.MethodPost:
|
||||
s.handleStorageReconnect(w, r)
|
||||
case r.URL.Path == "/api/storage/restart-apps" && r.Method == http.MethodPost:
|
||||
s.handleStorageRestartApps(w, r)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
@@ -421,7 +432,8 @@ func (s *Server) finalizeDecommissionWith(ctx context.Context, agent diskAgent,
|
||||
if err := s.settings.SetDecommissioned(where, migratedTo); err != nil {
|
||||
return fmt.Errorf("nyilvántartás frissítése sikertelen: %w", err)
|
||||
}
|
||||
if _, err := agent.Decommission(ctx, where); err != nil {
|
||||
// Registered path is the STABLE /mnt/felhom-drives/<name>; the agent decommissions the raw mount.
|
||||
if _, err := agent.Decommission(ctx, agentWhere(where)); err != nil {
|
||||
return fmt.Errorf("a meghajtó leszerelése sikertelen: %w", err)
|
||||
}
|
||||
if s.stackMgr != nil {
|
||||
@@ -715,7 +727,8 @@ func (s *Server) handleStorageEject(w http.ResponseWriter, r *http.Request) {
|
||||
writeDiskJSON(w, http.StatusServiceUnavailable, false, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
res, err := agent.EjectDisk(r.Context(), req.Where)
|
||||
// The registered path is the STABLE /mnt/felhom-drives/<name>; the agent operates on the raw mount.
|
||||
res, err := agent.EjectDisk(r.Context(), agentWhere(req.Where))
|
||||
if err != nil {
|
||||
writeDiskJSON(w, http.StatusBadGateway, false, err.Error(), nil)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user