F20-BUG2 + F9-reporting: /disks surfaces wipe_durable_id (gate scheme) + guest_attached

F20-BUG2: the /disks list only carried DurableID in the uuid: scheme (for /disks/assign),
but the wipe gate resolves devices in the byid:/byuuid: scheme — so a customer confirming a
wipe with the advertised id was refused (binding_mismatch). Added a shared s.deviceDurableID
seam used by BOTH handleDisks (new DiskInfo.WipeDurableID) and the format gate, so the id the
customer copies from the list is exactly the id the gate accepts. DurableID (uuid:) is unchanged
(still feeds assign).

F9 (reporting half): added DiskInfo.GuestAttached — whether the drive's namespace is actually
bound into THIS guest's config (guestBoundPaths), distinct from mere host presence (State). This
is the signal whose absence made the HDD look available when it wasn't attached, and resolves the
F2 hdd_configured-vs-/disks disagreement.

Tests: wipe_durable_id is the gate scheme + distinct from uuid:; the list's wipe id matches the
gate's device-id binding (no mismatch); guest_attached true iff bound into the guest.
This commit is contained in:
2026-06-14 15:00:56 +02:00
parent b566fbe57f
commit a2a76e7624
4 changed files with 177 additions and 6 deletions
+8
View File
@@ -154,6 +154,13 @@ type Server struct {
// override it to avoid touching real /dev.
reresolveWipe func(ctx context.Context, durableID string) (string, error)
// deviceDurableID derives the WIPE-binding durable id of a block device (the byid:/byuuid: scheme
// the wipe gate resolves against). F20-BUG2: BOTH the /disks list (DiskInfo.WipeDurableID) and the
// format gate use this single seam, so the id the customer copies from the list is exactly the id
// the gate accepts (no more uuid: vs byid: binding_mismatch). Defaults to storage.DeviceDurableID;
// tests override it. (DiskInfo.DurableID stays the uuid: storage id — that one feeds /disks/assign.)
deviceDurableID func(device string) (string, error)
jobsMu sync.Mutex
jobs map[int]*backupJob // per-guest backup job state (slice 8B)
@@ -197,6 +204,7 @@ func NewServer(o Options) (*Server, error) {
jobs: map[int]*backupJob{},
}
s.reresolveWipe = s.reresolveDurableForWipe
s.deviceDurableID = storage.DeviceDurableID
return s, nil
}