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

Feature: RTT helpers for NGS endpoints #921

Closed
wants to merge 6 commits into from
Closed
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
183 changes: 183 additions & 0 deletions cli/ngs_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
package cli

import (
"errors"
"fmt"
"strings"

"github.com/choria-io/fisk"
"github.com/nats-io/nats.go"
)

type ngsCmd struct {
rttCmd rttCmd

cloudAWS bool
cloudAZ bool
cloudGCP bool
cloudAll bool

regionalAsia bool
regionalEU bool
regionalUS bool
regionalUSWest bool
regionalUSEast bool
regionalAll bool

global bool
all bool
}

func configureNgsCommand(app commandHost) {
c := &ngsCmd{
rttCmd: rttCmd{},
}

ngs := app.Command("ngs", "NGS helpers")
ngs.HelpLong("WARNING: This command is experimental")

rtt := ngs.Command("rtt", "Displays RTT for all NGS endpoints. See: https://docs.synadia.com/ngs/resources/connection-endpoints").Action(c.rttHandler)
rtt.Arg("iterations", "How many round trips to do when testing each NGS endpoint").Default("3").IntVar(&c.rttCmd.iterations)
rtt.Flag("global", fmt.Sprintf("query default (global) endpoint: %s", globalEp)).Short('g').UnNegatableBoolVar(&c.global)
rtt.Flag("all-clouds", "query all Cloud Endpoints (AWS, AZ, GCP)").Short('c').UnNegatableBoolVar(&c.cloudAll)
rtt.Flag("aws", fmt.Sprintf("query AWS Cloud Endpoint: %s", cloudAWSEp)).UnNegatableBoolVar(&c.cloudAWS)
rtt.Flag("az", fmt.Sprintf("query AZ Cloud Endpoint: %s", cloudAZEp)).UnNegatableBoolVar(&c.cloudAZ)
rtt.Flag("gpc", fmt.Sprintf("query GCP Cloud Endpoint: %s", cloudGCPEp)).UnNegatableBoolVar(&c.cloudGCP)
rtt.Flag("all-regions", "query all Regional Endpoints (Asia, EU, US)").Short('r').UnNegatableBoolVar(&c.regionalAll)
rtt.Flag("asia", fmt.Sprintf("query regional endpoint in Asia: %s", regionalAsia)).UnNegatableBoolVar(&c.regionalAsia)
rtt.Flag("eu", fmt.Sprintf("query regional endpoint in EU: %s", regionalEU)).UnNegatableBoolVar(&c.regionalEU)
rtt.Flag("us", fmt.Sprintf("query regional endpoint in US: %s", regionalUS)).UnNegatableBoolVar(&c.regionalUS)
rtt.Flag("us-east", fmt.Sprintf("query regional endpoint in US East: %s", regionalUSEast)).UnNegatableBoolVar(&c.regionalUSEast)
rtt.Flag("us-west", fmt.Sprintf("query regional endpoint in US West: %s", regionalUSWest)).UnNegatableBoolVar(&c.regionalUSWest)
rtt.Flag("all", "query all available endpoints").Short('a').UnNegatableBoolVar(&c.all)
}

func init() {
registerCommand("ngs", 0, configureNgsCommand)
}

const (
globalEp = "tls://connect.ngs.global"
cloudAWSEp = "tls://aws.cloud.ngs.global"
cloudAZEp = "tls://az.cloud.ngs.global"
cloudGCPEp = "tls://gcp.cloud.ngs.global"
regionalAsia = "tls://asia.geo.ngs.global"
regionalEU = "tls://eu.geo.ngs.global"
regionalUS = "tls://us.geo.ngs.global"
regionalUSWest = "tls://west.us.geo.ngs.global"
regionalUSEast = "tls://east.us.geo.ngs.global"
)

var (
cloudEp = []string{
cloudAWSEp,
cloudAZEp,
cloudGCPEp,
}
reginalEp = []string{
regionalAsia,
regionalEU,
regionalUS,
regionalUSWest,
regionalUSEast,
}
allEp = []string{
globalEp,
cloudAWSEp,
cloudAZEp,
cloudGCPEp,
regionalAsia,
regionalEU,
regionalUS,
regionalUSWest,
regionalUSEast,
}
)

func (c *ngsCmd) rttHandler(_ *fisk.ParseContext) error {
servers := c.resolveServers()

targets, err := c.rttCmd.targets(servers)
if err != nil {
return err
}

err = c.rttCmd.performTest(targets)
if err != nil {
if errors.Is(err, nats.ErrAuthorization) {
fmt.Println("NGS server configuration needs to be specified (using context or flags).")
}
return err
}

table := newTableWriter("NGS Endpoints")
table.AddHeaders("Endpoint", "RTT")

for _, t := range targets {
rtts := ""
f := fmt.Sprintf("%%%ds: %%v\n", c.rttCmd.calcIndent(targets, 3))
for _, rtt := range t.Results {
rtts += fmt.Sprintf(f, rtt.Address, rtt.RTT)
}
table.AddRow(t.URL, rtts)
table.AddSeparator()
}

fmt.Println(table.Render())
return nil
}

func (c *ngsCmd) resolveServers() string {
fmtRes := func(res []string) string {
return strings.Join(res, ",")
}

if c.all {
return fmtRes(allEp)
}

servers := []string{}
if c.global {
servers = append(servers, globalEp)
}

if c.cloudAll {
servers = append(servers, cloudEp...)
} else {
if c.cloudAWS {
servers = append(servers, cloudAWSEp)
}
if c.cloudAZ {
servers = append(servers, cloudAZEp)
}
if c.cloudGCP {
servers = append(servers, cloudGCPEp)
}
}

if c.regionalAll {
servers = append(servers, reginalEp...)
} else {
if c.regionalAsia {
servers = append(servers, regionalAsia)
}
if c.regionalEU {
servers = append(servers, regionalEU)
}
if c.regionalUS {
servers = append(servers, regionalUS)
}
if c.regionalUSEast {
servers = append(servers, regionalUSEast)
}
if c.regionalUSWest {
servers = append(servers, regionalUSWest)
}
}

if len(servers) == 0 {
servers = append((servers), globalEp)
}

return fmtRes(servers)
}
13 changes: 10 additions & 3 deletions cli/rtt_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ func init() {
}

func (c *rttCmd) rtt(_ *fisk.ParseContext) error {
targets, err := c.targets()
servers, err := c.resolveServers()
if err != nil {
return err
}
targets, err := c.targets(servers)
if err != nil {
return err
}
Expand Down Expand Up @@ -164,16 +168,19 @@ func (c *rttCmd) calcRTT(server string, copts []nats.Option) (string, time.Durat
return nc.ConnectedUrl(), totalTime / time.Duration(c.iterations), nil
}

func (c *rttCmd) targets() (targets []*rttTarget, err error) {
func (c *rttCmd) resolveServers() (string, error) {
servers := ""
if opts.Conn != nil {
servers = strings.Join(opts.Conn.DiscoveredServers(), ",")
} else if opts.Config != nil {
servers = opts.Config.ServerURL()
} else {
return nil, fmt.Errorf("cannot find a server list to test")
return "", fmt.Errorf("cannot find a server list to test")
}
return servers, nil
}

func (c *rttCmd) targets(servers string) (targets []*rttTarget, err error) {
for _, s := range strings.Split(servers, ",") {
if !strings.Contains(s, "://") {
s = fmt.Sprintf("nats://%s", s)
Expand Down
Loading