mirror of
https://github.com/siderolabs/talos.git
synced 2025-10-08 14:11:13 +02:00
* Clear the input form and switch to summary tab after the network config is saved. * Use nodeaddress resource for detecting and displaying IPs. Improve the IP filtering logic. * Fix the logic of gateway detection. Display all gateways instead of a single one. * Use hostnamestatus resource to detect the hostname instead of an API call. * Add hostname entry to the network info section on summary tab (as `HOST`). * Enable `OUTBOUND` entry in network info section on summary tab. * Display only the physical network interfaces in the interface dropdown on network config tab. * Improve form input handling. * Additional minor fixes & improvements. Closes siderolabs/talos#6992. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
298 lines
5.6 KiB
Go
298 lines
5.6 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 apidata
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
|
|
|
"github.com/siderolabs/talos/pkg/machinery/client"
|
|
)
|
|
|
|
// Source is a data source that gathers information about a Talos node using Talos API.
|
|
type Source struct {
|
|
*client.Client
|
|
|
|
Interval time.Duration
|
|
|
|
ctx context.Context //nolint:containedctx
|
|
ctxCancel context.CancelFunc
|
|
|
|
wg sync.WaitGroup
|
|
}
|
|
|
|
// Run the data poll on interval.
|
|
func (source *Source) Run(ctx context.Context) <-chan *Data {
|
|
dataCh := make(chan *Data)
|
|
|
|
source.ctx, source.ctxCancel = context.WithCancel(ctx)
|
|
|
|
source.wg.Add(1)
|
|
|
|
go source.run(dataCh)
|
|
|
|
return dataCh
|
|
}
|
|
|
|
// Stop the data collection process.
|
|
func (source *Source) Stop() {
|
|
source.ctxCancel()
|
|
|
|
source.wg.Wait()
|
|
}
|
|
|
|
func (source *Source) run(dataCh chan<- *Data) {
|
|
defer source.wg.Done()
|
|
defer close(dataCh)
|
|
|
|
ticker := time.NewTicker(source.Interval)
|
|
defer ticker.Stop()
|
|
|
|
var oldData, currentData *Data
|
|
|
|
for {
|
|
currentData = source.gather()
|
|
|
|
if oldData == nil {
|
|
currentData.CalculateDiff(currentData)
|
|
} else {
|
|
currentData.CalculateDiff(oldData)
|
|
}
|
|
|
|
select {
|
|
case dataCh <- currentData:
|
|
case <-source.ctx.Done():
|
|
return
|
|
}
|
|
|
|
select {
|
|
case <-source.ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
}
|
|
|
|
oldData = currentData
|
|
}
|
|
}
|
|
|
|
//nolint:gocyclo,cyclop
|
|
func (source *Source) gather() *Data {
|
|
result := &Data{
|
|
Timestamp: time.Now(),
|
|
Nodes: map[string]*Node{},
|
|
}
|
|
|
|
var resultLock sync.Mutex
|
|
|
|
gatherFuncs := []func() error{
|
|
func() error {
|
|
resp, err := source.MachineClient.LoadAvg(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].LoadAvg = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.Version(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].Version = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.Memory(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].Memory = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.SystemStat(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].SystemStat = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.CPUInfo(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].CPUsInfo = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.NetworkDeviceStats(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].NetDevStats = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.DiskStats(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].DiskStats = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.Processes(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].Processes = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
func() error {
|
|
resp, err := source.MachineClient.ServiceList(source.ctx, &emptypb.Empty{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
resultLock.Lock()
|
|
defer resultLock.Unlock()
|
|
|
|
for _, msg := range resp.GetMessages() {
|
|
node := msg.GetMetadata().GetHostname()
|
|
|
|
if _, ok := result.Nodes[node]; !ok {
|
|
result.Nodes[node] = &Node{}
|
|
}
|
|
|
|
result.Nodes[node].ServiceList = msg
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var eg errgroup.Group
|
|
|
|
for _, f := range gatherFuncs {
|
|
eg.Go(f)
|
|
}
|
|
|
|
if err := eg.Wait(); err != nil {
|
|
// TODO: handle error
|
|
_ = err
|
|
}
|
|
|
|
return result
|
|
}
|