From 9d34158500a155a7065e259d68f588112c5834ea Mon Sep 17 00:00:00 2001 From: Utku Ozdemir Date: Fri, 2 Aug 2024 16:49:14 +0200 Subject: [PATCH] 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 --- internal/pkg/dashboard/apidata/source.go | 28 ++++++++++++++------- internal/pkg/dashboard/dashboard.go | 26 ++++++------------- internal/pkg/dashboard/logdata/logdata.go | 14 ++++++++--- internal/pkg/dashboard/resolver/resolver.go | 27 ++++++++++++++++++++ 4 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 internal/pkg/dashboard/resolver/resolver.go diff --git a/internal/pkg/dashboard/apidata/source.go b/internal/pkg/dashboard/apidata/source.go index e9a3da497..e8646339b 100644 --- a/internal/pkg/dashboard/apidata/source.go +++ b/internal/pkg/dashboard/apidata/source.go @@ -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) +} diff --git a/internal/pkg/dashboard/dashboard.go b/internal/pkg/dashboard/dashboard.go index ec5ad7b21..06056631c 100644 --- a/internal/pkg/dashboard/dashboard.go +++ b/internal/pkg/dashboard/dashboard.go @@ -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: diff --git a/internal/pkg/dashboard/logdata/logdata.go b/internal/pkg/dashboard/logdata/logdata.go index 7bd20f817..63fb63095 100644 --- a/internal/pkg/dashboard/logdata/logdata.go +++ b/internal/pkg/dashboard/logdata/logdata.go @@ -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 diff --git a/internal/pkg/dashboard/resolver/resolver.go b/internal/pkg/dashboard/resolver/resolver.go new file mode 100644 index 000000000..702401fea --- /dev/null +++ b/internal/pkg/dashboard/resolver/resolver.go @@ -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 +}