agent v0.36.1: decommission keeps raw mounted (re-enrollable)

The decommission unmounted the raw /mnt/<name>, orphaning a non-removable drive
so re-enroll bound an empty dir. Now DetachDrive only (bind under parent); raw
stays mounted so re-enroll re-binds. Test: raw NOT unmounted + DetachDrive called.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 20:06:23 +02:00
parent 05be509e6e
commit 281c7b7e3f
4 changed files with 28 additions and 12 deletions
+5 -6
View File
@@ -360,12 +360,11 @@ func (s *Server) handleDiskDecommission(w http.ResponseWriter, r *http.Request,
}
}
}
// Unmount (mirror eject) — benign, data preserved. NEVER format/mkfs here.
if err := s.disks.Unmount(r.Context(), req.Where); err != nil {
s.logger.Error("local-api: disk decommission", "vmid", vmid, "where", req.Where, "err", err)
writeErr(w, http.StatusBadRequest, "decommission failed: "+err.Error())
return
}
// Intermediary model: decommission is a LOGICAL retire (data stays, re-enrollable). It DetachDrive'd
// the bind under the parent above (the drive is no longer visible to the guest); it does NOT unmount
// the RAW /mnt/<name> host mount — that would orphan the drive (a non-removable SATA drive doesn't get
// re-plugged), so a one-click re-enroll (H3) could not re-bind it. The soft decommission marker blocks
// scheduling; physical removal is the separate "remove from system" action. NEVER format/mkfs here.
writeOK(w, map[string]any{"vmid": vmid, "decommissioned": req.Where, "dependent_guests": dependents})
}