mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-07 05:31:20 +02:00
Move dashboard package into a common location where both Talos and talosctl can use it. Add support for overriding stdin, stdout, stderr and ctt in process runner. Create a dashboard service which runs the dashboard on /dev/tty2. Redirect kernel messages to tty1 and switch to tty2 after starting the dashboard on it. Related to siderolabs/talos#6841, siderolabs/talos#4791. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
201 lines
5.1 KiB
Go
201 lines
5.1 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package data
|
|
|
|
import (
|
|
"github.com/siderolabs/gen/slices"
|
|
|
|
"github.com/siderolabs/talos/pkg/machinery/api/machine"
|
|
)
|
|
|
|
// Node represents data gathered from a single node.
|
|
type Node struct {
|
|
// These fields are directly API responses.
|
|
Hostname *machine.Hostname
|
|
LoadAvg *machine.LoadAvg
|
|
Version *machine.Version
|
|
Memory *machine.Memory
|
|
SystemStat *machine.SystemStat
|
|
CPUsInfo *machine.CPUsInfo
|
|
NetDevStats *machine.NetworkDeviceStats
|
|
DiskStats *machine.DiskStats
|
|
Processes *machine.Process
|
|
|
|
// These fields are calculated as diff with Node data from previous pol.
|
|
SystemStatDiff *machine.SystemStat
|
|
NetDevStatsDiff *machine.NetworkDeviceStats
|
|
DiskStatsDiff *machine.DiskStats
|
|
ProcsDiff map[int32]*machine.ProcessInfo
|
|
|
|
// Time-series data.
|
|
Series map[string][]float64
|
|
}
|
|
|
|
// MemUsage as used/total.
|
|
func (node *Node) MemUsage() float64 {
|
|
memTotal := node.Memory.GetMeminfo().GetMemtotal()
|
|
memUsed := node.Memory.GetMeminfo().GetMemtotal() - node.Memory.GetMeminfo().GetMemfree() - node.Memory.GetMeminfo().GetCached() - node.Memory.GetMeminfo().GetBuffers()
|
|
|
|
if memTotal == 0 {
|
|
return 0
|
|
}
|
|
|
|
return float64(memUsed) / float64(memTotal)
|
|
}
|
|
|
|
// CPUUsageByName returns CPU usage by name.
|
|
//
|
|
//nolint:gocyclo
|
|
func (node *Node) CPUUsageByName(name string) float64 {
|
|
if node.SystemStatDiff == nil || node.SystemStatDiff.CpuTotal == nil {
|
|
return 0
|
|
}
|
|
|
|
stat := node.SystemStatDiff.CpuTotal
|
|
|
|
idle := stat.Idle + stat.Iowait
|
|
nonIdle := stat.User + stat.Nice + stat.System + stat.Irq + stat.Steal + stat.SoftIrq
|
|
total := idle + nonIdle
|
|
|
|
if total == 0 {
|
|
return 0
|
|
}
|
|
|
|
switch name {
|
|
case "user":
|
|
return stat.User / total
|
|
case "system":
|
|
return stat.System / total
|
|
case "idle":
|
|
return stat.Idle / total
|
|
case "iowait":
|
|
return stat.Iowait / total
|
|
case "nice":
|
|
return stat.Nice / total
|
|
case "irq":
|
|
return stat.Irq / total
|
|
case "steal":
|
|
return stat.Steal / total
|
|
case "softirq":
|
|
return stat.SoftIrq / total
|
|
case "usage":
|
|
return (total - idle) / total
|
|
case "total":
|
|
return total
|
|
case "total_weighted":
|
|
cpuCount := len(node.CPUsInfo.GetCpuInfo())
|
|
if cpuCount == 0 {
|
|
return total
|
|
}
|
|
|
|
return total / float64(cpuCount)
|
|
}
|
|
|
|
panic("unknown cpu usage name")
|
|
}
|
|
|
|
// CtxSwitches returns diff of context switches.
|
|
func (node *Node) CtxSwitches() uint64 {
|
|
if node.SystemStatDiff == nil {
|
|
return 0
|
|
}
|
|
|
|
return node.SystemStatDiff.GetContextSwitches()
|
|
}
|
|
|
|
// ProcsCreated returns diff of processes created.
|
|
func (node *Node) ProcsCreated() uint64 {
|
|
if node.SystemStatDiff == nil {
|
|
return 0
|
|
}
|
|
|
|
return node.SystemStatDiff.GetProcessCreated()
|
|
}
|
|
|
|
// UpdateSeries builds time-series data based on previous iteration data.
|
|
func (node *Node) UpdateSeries(old *Node) {
|
|
node.Series = make(map[string][]float64)
|
|
|
|
for _, graphInfo := range []struct {
|
|
name string
|
|
f func() float64
|
|
}{
|
|
{
|
|
"mem",
|
|
node.MemUsage,
|
|
},
|
|
{
|
|
"user",
|
|
func() float64 { return node.CPUUsageByName("user") },
|
|
},
|
|
{
|
|
"system",
|
|
func() float64 { return node.CPUUsageByName("system") },
|
|
},
|
|
{
|
|
"loadavg",
|
|
func() float64 { return node.LoadAvg.GetLoad1() },
|
|
},
|
|
{
|
|
"netrxbytes",
|
|
func() float64 { return float64(node.NetDevStatsDiff.GetTotal().GetRxBytes()) },
|
|
},
|
|
{
|
|
"nettxbytes",
|
|
func() float64 { return float64(node.NetDevStatsDiff.GetTotal().GetTxBytes()) },
|
|
},
|
|
{
|
|
"diskrdsectors",
|
|
func() float64 { return float64(node.DiskStatsDiff.GetTotal().GetReadSectors()) },
|
|
},
|
|
{
|
|
"diskwrsectors",
|
|
func() float64 { return float64(node.DiskStatsDiff.GetTotal().GetWriteSectors()) },
|
|
},
|
|
} {
|
|
oldSeries := old.Series[graphInfo.name]
|
|
|
|
off := 0
|
|
if len(oldSeries) > maxPoints {
|
|
off = len(oldSeries) - maxPoints
|
|
}
|
|
|
|
node.Series[graphInfo.name] = append(oldSeries[off:], graphInfo.f())
|
|
|
|
// TODO: bug with plot widget
|
|
for len(node.Series[graphInfo.name]) < 2 {
|
|
node.Series[graphInfo.name] = append([]float64{0.0}, node.Series[graphInfo.name]...)
|
|
}
|
|
}
|
|
}
|
|
|
|
// UpdateDiff calculates diff with node data from previous iteration.
|
|
func (node *Node) UpdateDiff(old *Node) {
|
|
node.SystemStatDiff = &machine.SystemStat{
|
|
// TODO: support other fields
|
|
CpuTotal: cpuInfoDiff(old.SystemStat.GetCpuTotal(), node.SystemStat.GetCpuTotal()),
|
|
ContextSwitches: node.SystemStat.ContextSwitches - old.SystemStat.ContextSwitches,
|
|
ProcessCreated: node.SystemStat.ProcessCreated - old.SystemStat.ProcessCreated,
|
|
}
|
|
|
|
node.NetDevStatsDiff = &machine.NetworkDeviceStats{
|
|
// TODO: support other fields
|
|
Total: netDevDiff(old.NetDevStats.GetTotal(), node.NetDevStats.GetTotal()),
|
|
}
|
|
|
|
node.DiskStatsDiff = &machine.DiskStats{
|
|
// TODO: support other fields
|
|
Total: diskStatDiff(old.DiskStats.GetTotal(), node.DiskStats.GetTotal()),
|
|
}
|
|
|
|
index := slices.ToMap(old.Processes.GetProcesses(), func(proc *machine.ProcessInfo) (int32, *machine.ProcessInfo) {
|
|
return proc.Pid, proc
|
|
})
|
|
|
|
node.ProcsDiff = slices.ToMap(node.Processes.GetProcesses(), func(proc *machine.ProcessInfo) (int32, *machine.ProcessInfo) {
|
|
return proc.Pid, procDiff(index[proc.Pid], proc)
|
|
})
|
|
}
|