clustvirt/cluster/stats.go
Matthew Stobbs de93204e3d migrate data gathering to libvirtxml parsing
- instead of getting all the data the hard way, use libvirtxml
  to parse the XML from libvirt
- this makes it more accurate, and more future proof when schema
  changes occur
- add pcidb to query devices better
2024-03-19 15:25:57 -06:00

369 lines
9.0 KiB
Go

package cluster
// ClusterStats is used to gather stats for the entire cluster
// Combined with StatsDiff, we can get some basic cluster wide stats tracking
type ClusterStats struct {
// CPU Statistics including number of CPUs
CPU CPUStats
// Memory provides information about the amount of memory, including free and
// allocated memory
Memory MemoryStats
// Storage provides information about storage pools, Only get's stats for active
// pools, and will not activate pools that are not already active.
// Trys to sort out shared file systems from local filesystems using the Type parameter
// of Host.StoragePoolInfo
Storage StorageStats
// Volume provides information on allocated volumes used in the cluster
Volume VolumeStats
// VM provides VM specific counters for the cluster
VM VMStats
// Host provides Host information for the cluster
Host HostStats
// Network provices available networks, and how many are shared between hosts
Network NetworkStats
// NetIF provides information about Libvirt allocated networks, usable by the
// libvirt cluster
NetIF NetIFStats
old *ClusterStats
c *Cluster
}
// CPUStats provides information about the number of CPUs, Cores,
// Threads, and Speed available to the cluster.
type CPUStats struct {
Sockets uint32
Cores uint32
Threads uint32
Allocated uint32
MHz uint64
}
// MemoryStats provies information about the amount of memory, including free and
// allocated memory. Allocated is the total allocated to Guests
type MemoryStats struct {
Total uint64
Free uint64
Buffers uint64
Cached uint64
Allocated uint64
}
// StorageStats provides information about the available storage pools in the cluster,
// including the amount of space available, allocated, and how many pools are shared
// between hosts
type StorageStats struct {
Total uint64
Used uint64
Free uint64
Active uint32
Inactive uint32
Pools uint32
}
// VolumeStats provides information about the number of volumes on the cluster.
// Counts volumes in shared storage (as detmermined by StorageStats) only once
type VolumeStats struct {
Total uint32
Active uint32
Inactive uint32
}
// VMStats provides information about the defined Virtual Machines on the cluster
type VMStats struct {
Count uint32
Started uint32
Stopped uint32
}
// HostStats provides informatoin about the number of hosts defined, and how many
// are currently available. An unavailable host will not have it's statistics counted
type HostStats struct {
Count uint32
Available uint32
Nodes uint32
}
// NetworkStats provides informatoin about the available Host network connections,
// including bridges and ethernet devices.
type NetworkStats struct {
Count uint32
Active uint32
Inactive uint32
}
// NetIFStats provides information about Libvirt defined networks
type NetIFStats struct {
Count uint32
Common uint32
Active uint32
Inactive uint32
}
// DeviceStats provides information about the number of allocatable devices in the
// cluster. These are PCI and USB devices.
type DeviceStats struct {
Count uint32
}
// SecretStats provides the number of secrets defined throughout the cluster.
// Shared secrets are only counted once, and are recognized by their UUID
type SecretStats struct {
Count uint32
Shared uint32
}
// ClusterStats is used to gather stats for the entire cluster
type StatDiff struct {
CPU CPUDiff
Memory MemoryDiff
Storage StorageStats
Volume VolumeDiff
VM VMDiff
Host HostDiff
Network NetworkDiff
}
type CPUDiff struct {
Sockets int
Cores int
Threads int
Allocated int
}
type MemoryDiff struct {
Total int64
Free int64
Buffers int64
Cached int64
Allocated int64
}
type StorageDiff struct {
Total int64
Used int64
Free int64
Active int64
Inactive int64
Pools int
}
type VolumeDiff struct {
Total int
Active int
Inactive int
}
type VMDiff struct {
Count int
Started int
Stopped int
}
type HostDiff struct {
Count int
Available int
}
type NetworkDiff struct {
Count int
Active int
Inactive int
}
// InitStats is given a cluster, which it then uses to load the initial statistics
// Does not close connections, but uses the host connections available to the
// cluster to add statistics together.
func InitStats(c *Cluster) *ClusterStats {
cs := &ClusterStats{
c: c,
}
return cs
}
// Update triggers the stats collector to refresh it's statistics
func (cs *ClusterStats) Update() {
cs.old = cs.copy()
cs.reset()
// Start looping through each host in the cluster, adding to the total
for _, h := range cs.c.hosts {
cs.Host.Count++
cs.Host.Available++
cs.CPU.Sockets += h.HostInfo.Sockets
cs.CPU.Cores += h.HostInfo.Cores
cs.CPU.Threads += h.HostInfo.Threads
cs.Memory.Total += h.NodeMemory.Total
cs.Memory.Free += h.NodeMemory.Free
cs.Memory.Buffers += h.NodeMemory.Buffers
cs.Memory.Cached += h.NodeMemory.Cached
// Storage Pool counting
cs.Storage.Pools += uint32(len(h.StoragePoolList))
countedSharedPools := map[string]struct{}{}
// Loop through available storage pools
for _, sp := range h.StoragePoolList {
if _, ok := countedSharedPools[sp.Name]; ok {
// Already counted this shared pool, move on
continue
}
if sp.HAEnabled {
countedSharedPools[sp.Name] = struct{}{}
}
if !sp.Active {
cs.Storage.Inactive++
continue
}
cs.Storage.Active++
cs.Storage.Total += sp.Capacity
cs.Storage.Used += sp.Allocation
cs.Storage.Free += sp.Capacity - sp.Allocation
// Volumes in the pool
cs.Volume.Total += uint32(len(sp.Volumes))
for range sp.Volumes {
cs.Volume.Active++
}
}
// VM Count
cs.VM.Count += uint32(len(h.VMList))
for _, vm := range h.VMList {
cs.CPU.Allocated += uint32(vm.VCPUs)
cs.Memory.Allocated += uint64(vm.Memory)
if vm.Active {
cs.VM.Started++
continue
}
cs.VM.Stopped++
}
// Network count
cs.Network.Count += uint32(len(h.NetworkList))
for _, ni := range h.NetworkList {
if ni.Active {
cs.Network.Active++
continue
}
cs.Network.Inactive++
}
}
}
// Diff returns a map of all the field and how they changed
func (cs *ClusterStats) Diff() StatDiff {
return StatDiff{
CPU: struct {
Sockets int
Cores int
Threads int
Allocated int
}{
Sockets: int(cs.CPU.Sockets) - int(cs.old.CPU.Sockets),
Cores: int(cs.CPU.Cores) - int(cs.old.CPU.Cores),
Threads: int(cs.CPU.Threads) - int(cs.old.CPU.Threads),
Allocated: int(cs.CPU.Allocated) - int(cs.old.CPU.Allocated),
},
Memory: struct {
Total int
Free int
Buffers int
Cached int
Allocated int
}{
Total: int(cs.old.Memory.Total - cs.Memory.Total),
Free: int(cs.old.Memory.Free - cs.Memory.Free),
Buffers: int(cs.old.Memory.Buffers - cs.Memory.Buffers),
Cached: int(cs.old.Memory.Cached - cs.Memory.Cached),
Allocated: int(cs.old.Memory.Allocated - cs.Memory.Allocated),
},
Storage: struct {
Total int
Used int
Free int
Active int
Inactive int
Pools int
Volumes struct {
Total int
Active int
Inactive int
}
}{
Total: int(cs.old.Storage.Total - cs.Storage.Total),
Used: int(cs.old.Storage.Used - cs.Storage.Used),
Free: int(cs.old.Storage.Free - cs.Storage.Free),
Active: int(cs.old.Storage.Active - cs.Storage.Active),
Inactive: int(cs.old.Storage.Inactive - cs.Storage.Inactive),
Pools: int(cs.old.Storage.Pools - cs.Storage.Pools),
Volumes: struct {
Total int
Active int
Inactive int
}{
Total: int(cs.old.Volume.Total - cs.Volume.Total),
Active: int(cs.old.Volume.Active - cs.Volume.Active),
Inactive: int(cs.old.Volume.Inactive - cs.Volume.Inactive),
},
},
VM: struct {
Count int
Started int
Stopped int
}{
Count: int(cs.old.VM.Count - cs.VM.Count),
Started: int(cs.old.VM.Started - cs.VM.Started),
Stopped: int(cs.old.VM.Stopped - cs.VM.Stopped),
},
Host: struct {
Count int
Available int
}{
Count: int(cs.old.Host.Count - cs.Host.Count),
Available: int(cs.old.Host.Available - cs.Host.Available),
},
Network: struct {
Count int
Active int
Inactive int
}{
Count: int(cs.old.Network.Count - cs.Network.Count),
Active: int(cs.old.Network.Active - cs.Network.Active),
Inactive: int(cs.old.Network.Inactive - cs.Network.Inactive),
},
}
}
// copy the clusterstats into a new clusterstatus object for comparison purposes
func (cs *ClusterStats) copy() *ClusterStats {
ncs := *cs
return &ncs
}
// reset all values to zero value
func (cs *ClusterStats) reset() {
cs.CPU.Sockets = 0
cs.CPU.Cores = 0
cs.CPU.Threads = 0
cs.CPU.Allocated = 0
cs.Memory.Total = 0
cs.Memory.Free = 0
cs.Memory.Buffers = 0
cs.Memory.Cached = 0
cs.Storage.Total = 0
cs.Storage.Used = 0
cs.Storage.Free = 0
cs.Storage.Active = 0
cs.Storage.Inactive = 0
cs.Storage.Pools = 0
cs.VM.Count = 0
cs.VM.Started = 0
cs.VM.Stopped = 0
cs.Host.Count = 0
cs.Host.Available = 0
cs.Network.Count = 0
cs.Network.Active = 0
cs.Network.Inactive = 0
}