Skip to content

Commit

Permalink
fix: fix graph diffs in dashboard when node aliases are used
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
utkuozdemir committed Aug 7, 2024
1 parent 9a126d7 commit 9d34158
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 32 deletions.
28 changes: 19 additions & 9 deletions internal/pkg/dashboard/apidata/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,17 @@ 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"
)

// Source is a data source that gathers information about a Talos node using Talos API.
type Source struct {
*client.Client

Resolver resolver.Resolver

Interval time.Duration

ctx context.Context //nolint:containedctx
Expand Down Expand Up @@ -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{}
Expand All @@ -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{}
Expand All @@ -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{}
Expand All @@ -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{}
Expand All @@ -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{}
Expand All @@ -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{}
Expand All @@ -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{}
Expand All @@ -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{}
Expand All @@ -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{}
Expand All @@ -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)
}
26 changes: 7 additions & 19 deletions internal/pkg/dashboard/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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()
})
Expand Down Expand Up @@ -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:
Expand Down
14 changes: 10 additions & 4 deletions internal/pkg/dashboard/logdata/logdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -34,6 +35,8 @@ type Data struct {
type Source struct {
client *client.Client

resolver resolver.Resolver

logCtxCancel context.CancelFunc

eg errgroup.Group
Expand All @@ -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),
}
}

Expand Down Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions internal/pkg/dashboard/resolver/resolver.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 9d34158

Please sign in to comment.