67 lines
1.5 KiB
Go
67 lines
1.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os/exec"
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type GuestMetrics struct {
|
|
VMID int `json:"vmid"`
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
Node string `json:"node"`
|
|
Status string `json:"status"`
|
|
CPU float64 `json:"cpu"`
|
|
MaxCPU float64 `json:"maxcpu"`
|
|
MemoryBytes uint64 `json:"mem"`
|
|
MaxMemory uint64 `json:"maxmem"`
|
|
Uptime uint64 `json:"uptime"`
|
|
Template int `json:"template"`
|
|
}
|
|
|
|
type GuestsMetrics struct {
|
|
Available bool `json:"available"`
|
|
Guests []GuestMetrics `json:"guests"`
|
|
}
|
|
|
|
type guestCollector struct {
|
|
mu sync.Mutex
|
|
cached GuestsMetrics
|
|
updatedAt time.Time
|
|
}
|
|
|
|
func (c *guestCollector) collect() GuestsMetrics {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
if time.Since(c.updatedAt) < 3*time.Second {
|
|
return c.cached
|
|
}
|
|
c.cached = readGuests()
|
|
c.updatedAt = time.Now()
|
|
return c.cached
|
|
}
|
|
|
|
func readGuests() GuestsMetrics {
|
|
if _, err := exec.LookPath("pvesh"); err != nil {
|
|
return GuestsMetrics{}
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
output, err := exec.CommandContext(ctx, "pvesh", "get", "/cluster/resources", "--type", "vm", "--output-format", "json").Output()
|
|
result := GuestsMetrics{Available: true}
|
|
if err != nil {
|
|
return result
|
|
}
|
|
if json.Unmarshal(output, &result.Guests) != nil {
|
|
return result
|
|
}
|
|
sort.Slice(result.Guests, func(i, j int) bool {
|
|
return result.Guests[i].VMID < result.Guests[j].VMID
|
|
})
|
|
return result
|
|
}
|