diff --git a/cmd/rpc/admin.go b/cmd/rpc/admin.go index af9d49e8b6..fcfd3a79e1 100644 --- a/cmd/rpc/admin.go +++ b/cmd/rpc/admin.go @@ -541,6 +541,35 @@ func (s *Server) PeerInfo(w http.ResponseWriter, _ *http.Request, _ httprouter.P }, http.StatusOK) } +func newSystemResourceUsage(pm *mem.VirtualMemoryStat, c []cpu.TimesStat, cp []float64, d *disk.UsageStat, ioCounters []net.IOCountersStat) (SystemResourceUsage, error) { + if len(cp) == 0 { + return SystemResourceUsage{}, fmt.Errorf("missing cpu percent stats") + } + if len(c) == 0 { + return SystemResourceUsage{}, fmt.Errorf("missing cpu time stats") + } + if len(ioCounters) == 0 { + return SystemResourceUsage{}, fmt.Errorf("missing network io stats") + } + return SystemResourceUsage{ + TotalRAM: pm.Total, + AvailableRAM: pm.Available, + UsedRAM: pm.Used, + UsedRAMPercent: pm.UsedPercent, + FreeRAM: pm.Free, + UsedCPUPercent: cp[0], + UserCPU: c[0].User, + SystemCPU: c[0].System, + IdleCPU: c[0].Idle, + TotalDisk: d.Total, + UsedDisk: d.Used, + UsedDiskPercent: d.UsedPercent, + FreeDisk: d.Free, + ReceivedBytesIO: ioCounters[0].BytesRecv, + WrittenBytesIO: ioCounters[0].BytesSent, + }, nil +} + // PeerBook retrieves the node's peer book func (s *Server) PeerBook(w http.ResponseWriter, _ *http.Request, _ httprouter.Params) { write(w, s.controller.P2P.GetBookPeers(), http.StatusOK) @@ -732,6 +761,11 @@ func (s *Server) ResourceUsage(w http.ResponseWriter, _ *http.Request, _ httprou write(w, err, http.StatusInternalServerError) return } + systemUsage, err := newSystemResourceUsage(pm, c, cp, d, ioCounters) + if err != nil { + write(w, err, http.StatusInternalServerError) + return + } write(w, resourceUsageResponse{ Process: ProcessResourceUsage{ Name: name, @@ -742,23 +776,7 @@ func (s *Server) ResourceUsage(w http.ResponseWriter, _ *http.Request, _ httprou MemoryPercent: float64(memPercent), CPUPercent: cpuPercent, }, - System: SystemResourceUsage{ - TotalRAM: pm.Total, - AvailableRAM: pm.Available, - UsedRAM: pm.Used, - UsedRAMPercent: pm.UsedPercent, - FreeRAM: pm.Free, - UsedCPUPercent: cp[0], - UserCPU: c[0].User, - SystemCPU: c[0].System, - IdleCPU: c[0].Idle, - TotalDisk: d.Total, - UsedDisk: d.Used, - UsedDiskPercent: d.UsedPercent, - FreeDisk: d.Free, - ReceivedBytesIO: ioCounters[0].BytesRecv, - WrittenBytesIO: ioCounters[0].BytesSent, - }, + System: systemUsage, }, http.StatusOK) } diff --git a/cmd/rpc/admin_test.go b/cmd/rpc/admin_test.go new file mode 100644 index 0000000000..052e27414f --- /dev/null +++ b/cmd/rpc/admin_test.go @@ -0,0 +1,59 @@ +package rpc + +import ( + "strings" + "testing" + + "github.com/shirou/gopsutil/cpu" + "github.com/shirou/gopsutil/disk" + "github.com/shirou/gopsutil/mem" + gnet "github.com/shirou/gopsutil/net" +) + +func TestNewSystemResourceUsageRequiresStats(t *testing.T) { + pm := &mem.VirtualMemoryStat{} + d := &disk.UsageStat{} + cpuTimes := []cpu.TimesStat{{User: 1}} + cpuPercent := []float64{2} + ioCounters := []gnet.IOCountersStat{{BytesRecv: 3}} + + tests := []struct { + name string + cpuTimes []cpu.TimesStat + cpuPercent []float64 + ioCounters []gnet.IOCountersStat + want string + }{ + {name: "missing cpu percent", cpuTimes: cpuTimes, ioCounters: ioCounters, want: "missing cpu percent stats"}, + {name: "missing cpu times", cpuPercent: cpuPercent, ioCounters: ioCounters, want: "missing cpu time stats"}, + {name: "missing io counters", cpuTimes: cpuTimes, cpuPercent: cpuPercent, want: "missing network io stats"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := newSystemResourceUsage(pm, tt.cpuTimes, tt.cpuPercent, d, tt.ioCounters) + if err == nil || !strings.Contains(err.Error(), tt.want) { + t.Fatalf("newSystemResourceUsage error = %v, want %q", err, tt.want) + } + }) + } +} + +func TestNewSystemResourceUsage(t *testing.T) { + pm := &mem.VirtualMemoryStat{Total: 10, Available: 9, Used: 1, UsedPercent: 10, Free: 8} + d := &disk.UsageStat{Total: 20, Used: 5, UsedPercent: 25, Free: 15} + cpuTimes := []cpu.TimesStat{{User: 1, System: 2, Idle: 3}} + cpuPercent := []float64{4} + ioCounters := []gnet.IOCountersStat{{BytesRecv: 5, BytesSent: 6}} + + got, err := newSystemResourceUsage(pm, cpuTimes, cpuPercent, d, ioCounters) + if err != nil { + t.Fatalf("newSystemResourceUsage returned error: %v", err) + } + if got.UsedCPUPercent != 4 || got.UserCPU != 1 || got.SystemCPU != 2 || got.IdleCPU != 3 { + t.Fatalf("unexpected CPU stats: %+v", got) + } + if got.TotalRAM != 10 || got.TotalDisk != 20 || got.ReceivedBytesIO != 5 || got.WrittenBytesIO != 6 { + t.Fatalf("unexpected resource stats: %+v", got) + } +}