Files
nadir-agent/internal/modules/system/info.go
T
urania d4364a6cb7
build-and-release / release (push) Successful in 2m39s
feat(system): enhance system architecture
2026-06-25 14:44:47 +02:00

79 lines
2.9 KiB
Go

package system
import (
"context"
"os"
"strconv"
"strings"
"time"
"github.com/danielgtaylor/huma/v2"
)
// SystemInfoBody is the dashboard overview: OS identity plus live CPU, memory,
// disk, load, network, and temperature readings. Every section is best-effort —
// a source that's unavailable (e.g. no thermal zones in a VM) yields a zero
// value or empty list rather than failing the whole call.
type SystemInfoBody struct {
OS OSInfo `json:"os" doc:"OS and kernel identity"`
CPU CPUInfo `json:"cpu" doc:"Processor model and core count"`
Memory MemoryInfo `json:"memory" doc:"RAM and swap usage in bytes"`
Load LoadInfo `json:"load" doc:"Load averages (1/5/15 min)"`
UptimeSec int64 `json:"uptime_seconds" example:"12490" doc:"Seconds since boot"`
BootTime string `json:"boot_time" example:"2026-06-19T12:08:00Z" doc:"Boot time (RFC3339, UTC)"`
Disks []DiskInfo `json:"disks" doc:"Mounted block-device filesystems"`
NetworkInterfaces []NetInterface `json:"network_interfaces" doc:"Network interfaces and their addresses"`
Temperatures []Temperature `json:"temperatures" doc:"Thermal sensor readings in Celsius"`
}
type GetInfoOutput struct{ Body SystemInfoBody }
func registerInfo(api huma.API, sampler *Sampler) {
huma.Register(api, huma.Operation{
OperationID: "system-get-info",
Method: "GET",
Path: "/api/system/info",
Summary: "Get system information",
Description: "Returns an overview for a dashboard: OS/kernel identity, CPU, " +
"memory and swap, mounted disks, load averages, uptime, network " +
"interfaces, and temperatures. All values come from cheap local reads " +
"(/proc, /sys, syscalls) with no D-Bus dependency; each section is " +
"best-effort.",
Tags: []string{tagSystem},
Metadata: op("read"),
Errors: readErrors,
}, func(ctx context.Context, _ *struct{}) (*GetInfoOutput, error) {
uptime, boot := uptimeAndBoot()
return &GetInfoOutput{Body: SystemInfoBody{
OS: osInfo(),
CPU: cpuInfo(),
Memory: memInfo(),
Load: loadInfo(sampler),
UptimeSec: uptime,
BootTime: boot.Format(time.RFC3339),
Disks: diskInfo(),
NetworkInterfaces: netInfo(),
Temperatures: tempInfo(),
}}, nil
})
}
// uptimeAndBoot reads /proc/uptime (seconds since boot) and derives boot time.
// On any read error it returns zero values rather than failing the request.
func uptimeAndBoot() (int64, time.Time) {
data, err := os.ReadFile("/proc/uptime")
if err != nil {
return 0, time.Time{}
}
fields := strings.Fields(string(data))
if len(fields) == 0 {
return 0, time.Time{}
}
secs, err := strconv.ParseFloat(fields[0], 64)
if err != nil {
return 0, time.Time{}
}
boot := time.Now().Add(-time.Duration(secs * float64(time.Second))).UTC()
return int64(secs), boot
}