fix: fix graph diffs in dashboard when node aliases are used
When `talosctl dashboard` is used with node "aliases" (e.g., node names or machine IDs in Omni) passed via `-n` flag, the graphs in the monitor tab were not rendered correctly: The matching of the old and current data were done incorrectly. Fix this by pushing node alias->IP resolution down to the (api & log) data sources of the dashboard, by passing a resolver to them. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
This commit is contained in:
parent
9a126d70e0
commit
9d34158500
@ -12,6 +12,8 @@ import (
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers"
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/resolver"
|
||||
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||
)
|
||||
|
||||
@ -19,6 +21,8 @@ import (
|
||||
type Source struct {
|
||||
*client.Client
|
||||
|
||||
Resolver resolver.Resolver
|
||||
|
||||
Interval time.Duration
|
||||
|
||||
ctx context.Context //nolint:containedctx
|
||||
@ -101,7 +105,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -122,7 +126,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -143,7 +147,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -164,7 +168,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -185,7 +189,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -206,7 +210,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -227,7 +231,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -248,7 +252,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -269,7 +273,7 @@ func (source *Source) gather() *Data {
|
||||
defer resultLock.Unlock()
|
||||
|
||||
for _, msg := range resp.GetMessages() {
|
||||
node := msg.GetMetadata().GetHostname()
|
||||
node := source.node(msg)
|
||||
|
||||
if _, ok := result.Nodes[node]; !ok {
|
||||
result.Nodes[node] = &Node{}
|
||||
@ -295,3 +299,9 @@ func (source *Source) gather() *Data {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (source *Source) node(msg helpers.Message) string {
|
||||
hostname := msg.GetMetadata().GetHostname()
|
||||
|
||||
return source.Resolver.Resolve(hostname)
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/apidata"
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/components"
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/logdata"
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/resolver"
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/resourcedata"
|
||||
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||
)
|
||||
@ -247,16 +248,19 @@ func buildDashboard(ctx context.Context, cli *client.Client, opts ...Option) (*D
|
||||
}
|
||||
}
|
||||
|
||||
nodeResolver := resolver.New(ipsToNodeAliases)
|
||||
|
||||
dashboard.apiDataSource = &apidata.Source{
|
||||
Client: cli,
|
||||
Interval: defOptions.interval,
|
||||
Resolver: nodeResolver,
|
||||
}
|
||||
|
||||
dashboard.resourceDataSource = &resourcedata.Source{
|
||||
COSI: cli.COSI,
|
||||
}
|
||||
|
||||
dashboard.logDataSource = logdata.NewSource(cli)
|
||||
dashboard.logDataSource = logdata.NewSource(cli, nodeResolver)
|
||||
|
||||
return dashboard, nil
|
||||
}
|
||||
@ -386,24 +390,18 @@ func (d *Dashboard) startDataHandler(ctx context.Context) func() error {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case nodeLog := <-d.logDataSource.LogCh:
|
||||
nodeAlias := d.attemptResolveIPToAlias(nodeLog.Node)
|
||||
|
||||
if time.Since(lastLogTime) < 50*time.Millisecond {
|
||||
d.app.QueueUpdate(func() {
|
||||
d.processLog(nodeAlias, nodeLog.Log, nodeLog.Error)
|
||||
d.processLog(nodeLog.Node, nodeLog.Log, nodeLog.Error)
|
||||
})
|
||||
} else {
|
||||
d.app.QueueUpdateDraw(func() {
|
||||
d.processLog(nodeAlias, nodeLog.Log, nodeLog.Error)
|
||||
d.processLog(nodeLog.Node, nodeLog.Log, nodeLog.Error)
|
||||
})
|
||||
}
|
||||
|
||||
lastLogTime = time.Now()
|
||||
case d.data = <-dataCh:
|
||||
d.data.Nodes = maps.Map(d.data.Nodes, func(key string, v *apidata.Node) (string, *apidata.Node) {
|
||||
return d.attemptResolveIPToAlias(key), v
|
||||
})
|
||||
|
||||
d.app.QueueUpdateDraw(func() {
|
||||
d.processAPIData()
|
||||
})
|
||||
@ -483,16 +481,6 @@ func (d *Dashboard) selectScreen(screen Screen) {
|
||||
d.footer.SelectScreen(string(screen))
|
||||
}
|
||||
|
||||
// attemptResolveIPToAlias attempts to resolve the given node IP to its alias as it appears in "nodes" in the context.
|
||||
// If the IP is not found in the context, the IP is returned as-is.
|
||||
func (d *Dashboard) attemptResolveIPToAlias(node string) string {
|
||||
if resolved, ok := d.ipsToNodeAliases[node]; ok {
|
||||
return resolved
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
// collectNodeIPsToNodeAliases probes all nodes in the context for their IP addresses by calling their .Version endpoint and maps them to the node aliases in the context.
|
||||
//
|
||||
// Sample output:
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/siderolabs/talos/cmd/talosctl/pkg/talos/helpers"
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/resolver"
|
||||
"github.com/siderolabs/talos/internal/pkg/dashboard/util"
|
||||
"github.com/siderolabs/talos/pkg/machinery/api/common"
|
||||
"github.com/siderolabs/talos/pkg/machinery/client"
|
||||
@ -34,6 +35,8 @@ type Data struct {
|
||||
type Source struct {
|
||||
client *client.Client
|
||||
|
||||
resolver resolver.Resolver
|
||||
|
||||
logCtxCancel context.CancelFunc
|
||||
|
||||
eg errgroup.Group
|
||||
@ -43,10 +46,11 @@ type Source struct {
|
||||
}
|
||||
|
||||
// NewSource initializes and returns Source data source.
|
||||
func NewSource(client *client.Client) *Source {
|
||||
func NewSource(client *client.Client, resolver resolver.Resolver) *Source {
|
||||
return &Source{
|
||||
client: client,
|
||||
LogCh: make(chan Data),
|
||||
client: client,
|
||||
resolver: resolver,
|
||||
LogCh: make(chan Data),
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,7 +86,9 @@ func (source *Source) tailNodeWithRetries(ctx context.Context, node string) erro
|
||||
}
|
||||
|
||||
if readErr != nil {
|
||||
source.LogCh <- Data{Node: node, Error: readErr.Error()}
|
||||
resolved := source.resolver.Resolve(node)
|
||||
|
||||
source.LogCh <- Data{Node: resolved, Error: readErr.Error()}
|
||||
}
|
||||
|
||||
// back off a bit before retrying
|
||||
|
27
internal/pkg/dashboard/resolver/resolver.go
Normal file
27
internal/pkg/dashboard/resolver/resolver.go
Normal file
@ -0,0 +1,27 @@
|
||||
// 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 resolver resolves the node names.
|
||||
package resolver
|
||||
|
||||
// Resolver resolves the node names.
|
||||
type Resolver struct {
|
||||
db map[string]string
|
||||
}
|
||||
|
||||
// New creates a new Resolver.
|
||||
func New(db map[string]string) Resolver {
|
||||
return Resolver{
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve attempts to resolve the node name.
|
||||
func (n *Resolver) Resolve(node string) string {
|
||||
if resolved, ok := n.db[node]; ok {
|
||||
return resolved
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user