Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpk: brokers list exposing Host/Port/Rack/UUID #23595

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/go/rpk/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.59.1
github.com/redpanda-data/common-go/rpadmin v0.1.6
github.com/redpanda-data/common-go/rpadmin v0.1.7
github.com/rs/xid v1.6.0
github.com/safchain/ethtool v0.4.1
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
Expand Down
4 changes: 2 additions & 2 deletions src/go/rpk/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,8 @@ github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJ
github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
github.com/redpanda-data/common-go/net v0.1.0 h1:JnJioRJuL961r1QXiJQ1tW9+yEaJfu8FpXnUmvQbwNM=
github.com/redpanda-data/common-go/net v0.1.0/go.mod h1:iOdNkjxM7a1T8F3cYHTaKIPFCHzzp/ia6TN+Z+7Tt5w=
github.com/redpanda-data/common-go/rpadmin v0.1.6 h1:OpKO0h5unnZq8n1RJ3G6Hr8HT8ff/Ma0or5X1BNIMcM=
github.com/redpanda-data/common-go/rpadmin v0.1.6/go.mod h1:I7umqhnMhIOSEnIA3fvLtdQU7QO/SbWGCwFfFDs3De4=
github.com/redpanda-data/common-go/rpadmin v0.1.7 h1:zj3HiZuvAdOvOdi7oyTn4FYOPulO7BhvhLx9acOy810=
github.com/redpanda-data/common-go/rpadmin v0.1.7/go.mod h1:I7umqhnMhIOSEnIA3fvLtdQU7QO/SbWGCwFfFDs3De4=
github.com/redpanda-data/go-avro/v2 v2.0.0-20240405204525-77b1144dc525 h1:vskZrV6q8W8flL0Ud23AJUYAd8ZgTadO45+loFnG2G0=
github.com/redpanda-data/go-avro/v2 v2.0.0-20240405204525-77b1144dc525/go.mod h1:3YqAM7pgS5vW/EH7naCjFqnAajSgi0f0CfMe1HGhLxQ=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
Expand Down
103 changes: 91 additions & 12 deletions src/go/rpk/pkg/cli/redpanda/admin/brokers/list.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,44 @@
package brokers

import (
"fmt"
"strings"

"github.com/redpanda-data/common-go/rpadmin"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/adminapi"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/config"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/out"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/redpanda"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

func newListCommand(fs afero.Fs, p *config.Params) *cobra.Command {
return &cobra.Command{
var decom bool
cmd := &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "List the brokers in your cluster",
Args: cobra.ExactArgs(0),
Long: `List the brokers in your cluster.

This command lists all brokers in the cluster, active and inactive, unless they have been decommissioned.
Using the "--include-decommissioned" flag, it lists decommissioned brokers with associated UUIDs too.

The output table contains the following columns:

ID Node ID, an exclusive identifier for a broker
HOST Internal RPC address for communication between brokers
PORT Internal RPC port for communication between brokers
RACK Assigned rack ID
daisukebe marked this conversation as resolved.
Show resolved Hide resolved
CORES Number of cores (shards) on a broker
MEMBERSHIP Whether a broker is decommissioned or not
IS-ALIVE Whether a broker is alive or offline
VERSION Broker version
UUID (Optional) Additional exclusive identifier for a broker

NOTE: The UUID column is hidden when the cluster doesn't expose the UUID in the Admin API, or the API call fails to retrieve UUIDs.
`,
Args: cobra.ExactArgs(0),
Run: func(cmd *cobra.Command, _ []string) {
p, err := p.LoadVirtualProfile(fs)
out.MaybeDie(err, "rpk unable to load config: %v", err)
Expand All @@ -26,27 +50,82 @@ func newListCommand(fs afero.Fs, p *config.Params) *cobra.Command {
bs, err := cl.Brokers(cmd.Context())
out.MaybeDie(err, "unable to request brokers: %v", err)

headers := []string{"Node-ID", "Num-Cores", "Membership-Status"}
headers := []string{"ID", "Host", "Port", "Rack", "Cores", "Membership", "Is-Alive", "Version"}

args := func(b *rpadmin.Broker) []interface{} {
ret := []interface{}{b.NodeID, b.NumCores, b.MembershipStatus}
version, _ := redpanda.VersionFromString(b.Version)
ret := []interface{}{b.NodeID, b.InternalRPCAddress, b.InternalRPCPort, formatOutput(b.Rack), b.NumCores, b.MembershipStatus, *b.IsAlive, formatOutput(version.String())}
return ret
}
for _, b := range bs {
if b.IsAlive != nil {
headers = append(headers, "Is-Alive", "Broker-Version")
orig := args
args = func(b *rpadmin.Broker) []interface{} {
return append(orig(b), *b.IsAlive, b.Version)
}
break

idUUIDMapping, err := cl.GetBrokerUuids(cmd.Context())
if err != nil {
fmt.Printf("unable to retrieve node UUIDs: %v", err)
}
if idUUIDMapping != nil {
headers = append(headers, "UUID")
org := args
args = func(b *rpadmin.Broker) []interface{} {
return append(org(b), mapUUID(b.NodeID, idUUIDMapping))
}
}

tw := out.NewTable(headers...)
defer tw.Flush()
for _, b := range bs {
tw.Print(args(&b)...)
}

if decom && idUUIDMapping != nil {
decomNodes := extractDecomNodes(bs, idUUIDMapping)
for _, b := range decomNodes {
tw.Print(b.NodeID, "-", "-", "-", "-", "-", "-", "-", b.UUID)
}
}
},
}
cmd.Flags().BoolVarP(&decom, "include-decommissioned", "d", false, "If true, include decommissioned brokers")
daisukebe marked this conversation as resolved.
Show resolved Hide resolved
return cmd
}

// mapUUID returns a UUID from "mapping" which node ID maps to "nodeID".
func mapUUID(nodeID int, mapping []rpadmin.BrokerUuids) string {
var UUIDs []string
for _, node := range mapping {
if nodeID == node.NodeID {
UUIDs = append(UUIDs, node.UUID)
}
}
if len(UUIDs) == 0 {
return "-"
}
return strings.Join(UUIDs, ", ")
}

// extractDecomNodes compares and returns nodes in brokerUUIDs (with UUIDs) not in brokers.
func extractDecomNodes(brokers []rpadmin.Broker, brokerUUIDs []rpadmin.BrokerUuids) []rpadmin.BrokerUuids {
activeNodeMap := make(map[int]bool)

for _, br := range brokers {
activeNodeMap[br.NodeID] = true
}

var decomNodes []rpadmin.BrokerUuids
for _, bu := range brokerUUIDs {
if !activeNodeMap[bu.NodeID] {
decomNodes = append(decomNodes, rpadmin.BrokerUuids{
NodeID: bu.NodeID,
UUID: bu.UUID,
})
}
}

return decomNodes
}

func formatOutput(s string) string {
if s == "" || s == "0.0.0" {
return "-"
}
return s
}
Loading