Support privileged fsinfo totals for guest disks (#1319)

This commit is contained in:
rcourtman 2026-03-27 11:18:53 +00:00
parent 2afde29a48
commit 1f332bee52
3 changed files with 73 additions and 13 deletions

View file

@ -1415,23 +1415,25 @@ func (c *Client) GetVMAgentVersion(ctx context.Context, node string, vmid int) (
// VMFileSystem represents filesystem information from QEMU guest agent
type VMFileSystem struct {
Name string `json:"name"`
Type string `json:"type"`
Mountpoint string `json:"mountpoint"`
TotalBytes uint64 `json:"total-bytes"`
UsedBytes uint64 `json:"used-bytes"`
Disk string // Extracted disk device name for duplicate detection
DiskRaw []interface{} `json:"disk"` // Raw disk device info from API
Name string `json:"name"`
Type string `json:"type"`
Mountpoint string `json:"mountpoint"`
TotalBytes uint64 `json:"total-bytes"`
TotalBytesPrivileged uint64 `json:"total-bytes-privileged"`
UsedBytes uint64 `json:"used-bytes"`
Disk string // Extracted disk device name for duplicate detection
DiskRaw []interface{} `json:"disk"` // Raw disk device info from API
}
func (fs *VMFileSystem) UnmarshalJSON(data []byte) error {
type rawVMFileSystem struct {
Name string `json:"name"`
Type string `json:"type"`
Mountpoint string `json:"mountpoint"`
TotalBytes interface{} `json:"total-bytes"`
UsedBytes interface{} `json:"used-bytes"`
DiskRaw []interface{} `json:"disk"`
Name string `json:"name"`
Type string `json:"type"`
Mountpoint string `json:"mountpoint"`
TotalBytes interface{} `json:"total-bytes"`
TotalBytesPrivileged interface{} `json:"total-bytes-privileged"`
UsedBytes interface{} `json:"used-bytes"`
DiskRaw []interface{} `json:"disk"`
}
var raw rawVMFileSystem
@ -1443,15 +1445,23 @@ func (fs *VMFileSystem) UnmarshalJSON(data []byte) error {
if err != nil {
return err
}
totalPrivileged, err := parseUint64Flexible(raw.TotalBytesPrivileged)
if err != nil {
return err
}
used, err := parseUint64Flexible(raw.UsedBytes)
if err != nil {
return err
}
if total == 0 && totalPrivileged > 0 {
total = totalPrivileged
}
fs.Name = raw.Name
fs.Type = raw.Type
fs.Mountpoint = raw.Mountpoint
fs.TotalBytes = total
fs.TotalBytesPrivileged = totalPrivileged
fs.UsedBytes = used
fs.DiskRaw = raw.DiskRaw
fs.Disk = ""

View file

@ -54,6 +54,45 @@ func TestClientVMFSInfoParsing(t *testing.T) {
}
}
func TestClientVMFSInfoParsingPrivilegedCapacityFallback(t *testing.T) {
client := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api2/json/nodes/node1/qemu/100/agent/get-fsinfo":
writeJSON(t, w, map[string]interface{}{
"data": map[string]interface{}{
"result": []map[string]interface{}{
{
"name": "windows",
"type": "ntfs",
"mountpoint": "C:\\Windows",
"total-bytes": 0,
"total-bytes-privileged": 500,
"used-bytes": 200,
},
},
},
})
default:
http.NotFound(w, r)
}
})
ctx := context.Background()
filesystems, err := client.GetVMFSInfo(ctx, "node1", 100)
if err != nil {
t.Fatalf("GetVMFSInfo error: %v", err)
}
if len(filesystems) != 1 {
t.Fatalf("expected 1 filesystem, got %d", len(filesystems))
}
if filesystems[0].TotalBytes != 500 {
t.Fatalf("expected privileged total-bytes fallback, got %d", filesystems[0].TotalBytes)
}
if filesystems[0].Disk != "C:" {
t.Fatalf("expected windows drive disk, got %q", filesystems[0].Disk)
}
}
func TestClientVMFSInfoObjectResult(t *testing.T) {
client := newTestClient(t, func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {

View file

@ -254,6 +254,17 @@ func TestVMFileSystemUnmarshalFlexibleNumbers(t *testing.T) {
t.Fatalf("unexpected float string values: got total=%d used=%d", fs.TotalBytes, fs.UsedBytes)
}
})
t.Run("falls back to total-bytes-privileged when total-bytes is missing", func(t *testing.T) {
payload := `{"name":"windows","type":"ntfs","mountpoint":"C:\\\\","total-bytes-privileged":536870912000,"used-bytes":214748364800}`
var fs VMFileSystem
if err := json.Unmarshal([]byte(payload), &fs); err != nil {
t.Fatalf("unexpected error unmarshalling privileged total-bytes: %v", err)
}
if fs.TotalBytes != 536870912000 || fs.TotalBytesPrivileged != 536870912000 || fs.UsedBytes != 214748364800 {
t.Fatalf("unexpected privileged values: got total=%d privileged=%d used=%d", fs.TotalBytes, fs.TotalBytesPrivileged, fs.UsedBytes)
}
})
}
func TestVMFileSystemUnmarshalJSON_InvalidValues(t *testing.T) {