From 6307cb5b5220e588b3c0799fa8525d16744fb1d2 Mon Sep 17 00:00:00 2001 From: Robert Glonek Date: Wed, 11 Sep 2024 18:39:55 -0700 Subject: [PATCH] inventory - add themes and no-notes switch --- CHANGELOG/7.6.0.md | 1 + src/backend.go | 4 +-- src/backendAws.go | 8 ++++-- src/backendDocker.go | 8 ++++-- src/backendGcp.go | 8 ++++-- src/cmdClientList.go | 4 ++- src/cmdClusterList.go | 4 ++- src/cmdInventoryList.go | 59 +++++++++++++++++++++++++++++------------ src/cmdTemplateList.go | 4 ++- 9 files changed, 72 insertions(+), 28 deletions(-) diff --git a/CHANGELOG/7.6.0.md b/CHANGELOG/7.6.0.md index 8f5ea289..346fa445 100644 --- a/CHANGELOG/7.6.0.md +++ b/CHANGELOG/7.6.0.md @@ -45,6 +45,7 @@ _Release Date: Month Day, Year_ * AWS: Expiry System: cleanup unused SSH keys. * AWS: `template vacuum` also vacuum template temporary SSH keys. * CI: Update all dependencies: brew install actions, rpm package, golang version and Packages. +* CLI: Add theme support for all inventory listings with `--theme=box|frame|nocolor` 3 options; allow `--no-notes` to disable extra notes * Client: Add eks client - eksctl bootstrap system. * Client: Open ports 8998 and 8182 for Vector and Graph clients. * Client: Vector: add support for centos-stream-9 base. diff --git a/src/backend.go b/src/backend.go index bae8bcd6..57a4ae0a 100644 --- a/src/backend.go +++ b/src/backend.go @@ -155,9 +155,9 @@ type backend interface { // returns a map of [int]string for a given cluster, where int is node number and string is the IP of said node GetNodeIpMap(name string, internalIPs bool) (map[int]string, error) // return formatted for printing cluster list - ClusterListFull(json bool, owner string, noPager bool, isPretty bool, sort []string, renderer string) (string, error) + ClusterListFull(json bool, owner string, noPager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) // return formatted for printing template list - TemplateListFull(json bool, noPager bool, isPretty bool, sort []string, renderer string) (string, error) + TemplateListFull(json bool, noPager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) // upload files to node Upload(clusterName string, node int, source string, destination string, verbose bool, legacy bool) error // download files from node diff --git a/src/backendAws.go b/src/backendAws.go index 70225104..4f158bae 100644 --- a/src/backendAws.go +++ b/src/backendAws.go @@ -2646,22 +2646,26 @@ func (d *backendAws) GetInstanceTags(name string) (map[string]map[string]string, return nodeList, nil } -func (d *backendAws) ClusterListFull(isJson bool, owner string, pager bool, isPretty bool, sort []string, renderer string) (string, error) { +func (d *backendAws) ClusterListFull(isJson bool, owner string, pager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) { a.opts.Inventory.List.Json = isJson a.opts.Inventory.List.Owner = owner a.opts.Inventory.List.Pager = pager a.opts.Inventory.List.JsonPretty = isPretty a.opts.Inventory.List.SortBy = sort a.opts.Inventory.List.RenderType = renderer + a.opts.Inventory.List.Theme = theme + a.opts.Inventory.List.NoNotes = noNotes return "", a.opts.Inventory.List.run(d.server, d.client, false, false, false) } -func (d *backendAws) TemplateListFull(isJson bool, pager bool, isPretty bool, sort []string, renderer string) (string, error) { +func (d *backendAws) TemplateListFull(isJson bool, pager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) { a.opts.Inventory.List.Json = isJson a.opts.Inventory.List.Pager = pager a.opts.Inventory.List.JsonPretty = isPretty a.opts.Inventory.List.SortBy = sort a.opts.Inventory.List.RenderType = renderer + a.opts.Inventory.List.Theme = theme + a.opts.Inventory.List.NoNotes = noNotes return "", a.opts.Inventory.List.run(false, false, true, false, false) } diff --git a/src/backendDocker.go b/src/backendDocker.go index 1e8a559b..da5fa4f4 100644 --- a/src/backendDocker.go +++ b/src/backendDocker.go @@ -1298,21 +1298,25 @@ func (d *backendDocker) copyFilesToContainer(name string, files []fileListReader } // returns an unformatted string with list of clusters, to be printed to user -func (d *backendDocker) ClusterListFull(isJson bool, owner string, pager bool, isPretty bool, sort []string, renderer string) (string, error) { +func (d *backendDocker) ClusterListFull(isJson bool, owner string, pager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) { a.opts.Inventory.List.Json = isJson a.opts.Inventory.List.Pager = pager a.opts.Inventory.List.JsonPretty = isPretty a.opts.Inventory.List.SortBy = sort a.opts.Inventory.List.RenderType = renderer + a.opts.Inventory.List.Theme = theme + a.opts.Inventory.List.NoNotes = noNotes return "", a.opts.Inventory.List.run(d.server, d.client, false, false, false) } // returns an unformatted string with list of clusters, to be printed to user -func (d *backendDocker) TemplateListFull(isJson bool, pager bool, isPretty bool, sort []string, renderer string) (string, error) { +func (d *backendDocker) TemplateListFull(isJson bool, pager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) { a.opts.Inventory.List.Json = isJson a.opts.Inventory.List.Pager = pager a.opts.Inventory.List.JsonPretty = isPretty a.opts.Inventory.List.SortBy = sort a.opts.Inventory.List.RenderType = renderer + a.opts.Inventory.List.Theme = theme + a.opts.Inventory.List.NoNotes = noNotes return "", a.opts.Inventory.List.run(false, false, true, false, false) } diff --git a/src/backendGcp.go b/src/backendGcp.go index e1a86e40..aa6cfde0 100644 --- a/src/backendGcp.go +++ b/src/backendGcp.go @@ -1705,13 +1705,15 @@ func (d *backendGcp) GetNodeIpMap(name string, internalIPs bool) (map[int]string return nlist, nil } -func (d *backendGcp) ClusterListFull(isJson bool, owner string, pager bool, isPretty bool, sort []string, renderer string) (string, error) { +func (d *backendGcp) ClusterListFull(isJson bool, owner string, pager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) { a.opts.Inventory.List.Json = isJson a.opts.Inventory.List.Owner = owner a.opts.Inventory.List.Pager = pager a.opts.Inventory.List.JsonPretty = isPretty a.opts.Inventory.List.SortBy = sort a.opts.Inventory.List.RenderType = renderer + a.opts.Inventory.List.Theme = theme + a.opts.Inventory.List.NoNotes = noNotes return "", a.opts.Inventory.List.run(d.server, d.client, false, false, false) } @@ -2375,12 +2377,14 @@ func (d *backendGcp) VacuumTemplates() error { return d.vacuum(nil) } -func (d *backendGcp) TemplateListFull(isJson bool, pager bool, isPretty bool, sort []string, renderer string) (string, error) { +func (d *backendGcp) TemplateListFull(isJson bool, pager bool, isPretty bool, sort []string, renderer string, theme string, noNotes bool) (string, error) { a.opts.Inventory.List.Json = isJson a.opts.Inventory.List.Pager = pager a.opts.Inventory.List.JsonPretty = isPretty a.opts.Inventory.List.SortBy = sort a.opts.Inventory.List.RenderType = renderer + a.opts.Inventory.List.Theme = theme + a.opts.Inventory.List.NoNotes = noNotes return "", a.opts.Inventory.List.run(false, false, true, false, false) } diff --git a/src/cmdClientList.go b/src/cmdClientList.go index e5965b30..a93c1d53 100644 --- a/src/cmdClientList.go +++ b/src/cmdClientList.go @@ -10,6 +10,8 @@ import ( type clientListCmd struct { Owner string `long:"owner" description:"Only show resources tagged with this owner"` SortBy []string `long:"sort-by" description:"sort by field name; must match exact header name; can be specified multiple times; format: asc:name dsc:name ascnum:name dscnum:name"` + Theme string `long:"theme" description:"for standard output, pick a theme: default|nocolor|frame|box"` + NoNotes bool `long:"no-notes" description:"for standard output, do not print extra notes below the tables"` Json bool `short:"j" long:"json" description:"Provide output in json format"` JsonPretty bool `short:"p" long:"pretty" description:"Provide json output with line-feeds and indentations"` Pager bool `long:"pager" description:"set to enable vertical and horizontal pager" simplemode:"false"` @@ -65,7 +67,7 @@ func (c *clientListCmd) Execute(args []string) error { } return nil } - f, e := b.ClusterListFull(c.Json, c.Owner, c.Pager, c.JsonPretty, c.SortBy, c.RenderType) + f, e := b.ClusterListFull(c.Json, c.Owner, c.Pager, c.JsonPretty, c.SortBy, c.RenderType, c.Theme, c.NoNotes) if e != nil { return e } diff --git a/src/cmdClusterList.go b/src/cmdClusterList.go index c4e5cd02..c61a3092 100644 --- a/src/cmdClusterList.go +++ b/src/cmdClusterList.go @@ -10,6 +10,8 @@ import ( type clusterListCmd struct { Owner string `long:"owner" description:"Only show resources tagged with this owner"` SortBy []string `long:"sort-by" description:"sort by field name; must match exact header name; can be specified multiple times; format: asc:name dsc:name ascnum:name dscnum:name"` + Theme string `long:"theme" description:"for standard output, pick a theme: default|nocolor|frame|box"` + NoNotes bool `long:"no-notes" description:"for standard output, do not print extra notes below the tables"` Json bool `short:"j" long:"json" description:"Provide output in json format"` JsonPretty bool `short:"p" long:"pretty" description:"Provide json output with line-feeds and indentations"` Pager bool `long:"pager" description:"set to enable vertical and horizontal pager" simplemode:"false"` @@ -63,7 +65,7 @@ func (c *clusterListCmd) Execute(args []string) error { } return nil } - f, e := b.ClusterListFull(c.Json, c.Owner, c.Pager, c.JsonPretty, c.SortBy, c.RenderType) + f, e := b.ClusterListFull(c.Json, c.Owner, c.Pager, c.JsonPretty, c.SortBy, c.RenderType, c.Theme, c.NoNotes) if e != nil { return e } diff --git a/src/cmdInventoryList.go b/src/cmdInventoryList.go index 397e0e1b..5e48f1e9 100644 --- a/src/cmdInventoryList.go +++ b/src/cmdInventoryList.go @@ -28,6 +28,8 @@ type inventoryListCmd struct { Owner string `long:"owner" description:"Only show resources tagged with this owner"` Pager bool `long:"pager" description:"set to enable vertical and horizontal pager" simplemode:"false"` SortBy []string `long:"sort-by" description:"sort by field name; must match exact header name; can be specified multiple times; format: asc:name dsc:name ascnum:name dscnum:name"` + Theme string `long:"theme" description:"for standard output, pick a theme: default|nocolor|frame|box"` + NoNotes bool `long:"no-notes" description:"for standard output, do not print extra notes below the tables"` Json bool `short:"j" long:"json" description:"Provide output in json format"` JsonPretty bool `short:"p" long:"pretty" description:"Provide json output with line-feeds and indentations"` AWSFull bool `long:"aws-full" description:"set to iterate through all regions and provide full output"` @@ -523,6 +525,9 @@ func (c *inventoryListCmd) run(showClusters bool, showClients bool, showTemplate warnExp := colorPrint{c: text.Colors{text.BgHiYellow, text.FgBlack}, enable: true} errExp := colorPrint{c: text.Colors{text.BgHiRed, text.FgWhite}, enable: true} isColor := true + if c.Theme == "nocolor" || c.Theme == "frame" || c.Theme == "box" { + isColor = false + } if _, ok := os.LookupEnv("NO_COLOR"); ok || os.Getenv("CLICOLOR") == "0" { isColor = false } @@ -561,9 +566,20 @@ func (c *inventoryListCmd) run(showClusters bool, showClients bool, showTemplate colorHiWhite.enable = false warnExp.enable = false errExp.enable = false - tstyle := t.Style() - tstyle.Options.DrawBorder = false - tstyle.Options.SeparateColumns = false + if c.Theme == "frame" { + t.SetStyle(table.StyleRounded) + tstyle := t.Style() + tstyle.Options.DrawBorder = true + tstyle.Options.SeparateColumns = false + } else if c.Theme == "box" { + t.SetStyle(table.StyleRounded) + tstyle := t.Style() + tstyle.Options.SeparateColumns = true + } else { + tstyle := t.Style() + tstyle.Options.DrawBorder = false + tstyle.Options.SeparateColumns = false + } } else { t.SetStyle(table.StyleColoredBlackOnCyanWhite) } @@ -716,12 +732,15 @@ func (c *inventoryListCmd) run(showClusters bool, showClients bool, showTemplate t.AppendRow(vv) } fmt.Println(render()) - if a.opts.Config.Backend.Type != "docker" { - fmt.Fprint(os.Stderr, "* instance Running Cost displays only the cost of owning the instance in a running state for the duration it was running so far. It does not account for taxes, disk, network or transfer costs.\n\n") - } else { - fmt.Fprint(os.Stderr, "* to connect directly to the cluster (non-docker-desktop), execute 'aerolab cluster list' and connect to the node IP on the given exposed port (or configured aerospike services port - default 3000)\n") - fmt.Fprint(os.Stderr, "* to connect to the cluster when using Docker Desktop, execute 'aerolab cluster list` and connect to IP 127.0.0.1:EXPOSED_PORT with a connect policy of `--services-alternate`\n\n") + if !c.NoNotes { + if a.opts.Config.Backend.Type != "docker" { + fmt.Fprint(os.Stdout, "* instance Running Cost displays only the cost of owning the instance in a running state for the duration it was running so far. It does not account for taxes, disk, network or transfer costs.\n") + } else { + fmt.Fprint(os.Stdout, "* to connect directly to the cluster (non-docker-desktop), execute 'aerolab cluster list' and connect to the node IP on the given exposed port (or configured aerospike services port - default 3000)\n") + fmt.Fprint(os.Stdout, "* to connect to the cluster when using Docker Desktop, execute 'aerolab cluster list` and connect to IP 127.0.0.1:EXPOSED_PORT with a connect policy of `--services-alternate`\n") + } } + fmt.Println("") } if showClients { @@ -784,11 +803,14 @@ func (c *inventoryListCmd) run(showClusters bool, showClients bool, showTemplate t.AppendRow(vv) } fmt.Println(render()) - if a.opts.Config.Backend.Type == "docker" { - fmt.Fprint(os.Stderr, "* if using Docker Desktop and forwaring ports by exposing them (-e ...), use IP 127.0.0.1 for the Access URL\n\n") - } else { - fmt.Fprint(os.Stderr, "* instance Running Cost displays only the cost of owning the instance in a running state for the duration it was running so far. It does not account for taxes, disk, network or transfer costs.\n\n") + if !c.NoNotes { + if a.opts.Config.Backend.Type == "docker" { + fmt.Fprint(os.Stdout, "* if using Docker Desktop and forwaring ports by exposing them (-e ...), use IP 127.0.0.1 for the Access URL\n") + } else { + fmt.Fprint(os.Stdout, "* instance Running Cost displays only the cost of owning the instance in a running state for the duration it was running so far. It does not account for taxes, disk, network or transfer costs.\n") + } } + fmt.Println("") } for _, showOther := range showOthers { @@ -1209,12 +1231,15 @@ func (c *inventoryListCmd) run(showClusters bool, showClients bool, showTemplate } } fmt.Println(render()) - if a.opts.Config.Backend.Type != "docker" { - fmt.Fprint(os.Stderr, "* instance Running Cost displays only the cost of owning the instance in a running state for the duration it was running so far. It does not account for taxes, disk, network or transfer costs.\n\n") - } else { - fmt.Fprint(os.Stderr, "* to connect directly to the cluster (non-docker-desktop), execute 'aerolab cluster list' and connect to the node IP on the given exposed port (or configured aerospike services port - default 3000)\n") - fmt.Fprint(os.Stderr, "* to connect to the cluster when using Docker Desktop, execute 'aerolab cluster list` and connect to IP 127.0.0.1:EXPOSED_PORT with a connect policy of `--services-alternate`\n\n") + if !c.NoNotes { + if a.opts.Config.Backend.Type != "docker" { + fmt.Fprint(os.Stdout, "* instance Running Cost displays only the cost of owning the instance in a running state for the duration it was running so far. It does not account for taxes, disk, network or transfer costs.\n") + } else { + fmt.Fprint(os.Stdout, "* to connect directly to the cluster (non-docker-desktop), execute 'aerolab cluster list' and connect to the node IP on the given exposed port (or configured aerospike services port - default 3000)\n") + fmt.Fprint(os.Stdout, "* to connect to the cluster when using Docker Desktop, execute 'aerolab cluster list` and connect to IP 127.0.0.1:EXPOSED_PORT with a connect policy of `--services-alternate`\n") + } } + fmt.Println("") } } diff --git a/src/cmdTemplateList.go b/src/cmdTemplateList.go index d73b377b..2da446b6 100644 --- a/src/cmdTemplateList.go +++ b/src/cmdTemplateList.go @@ -4,6 +4,8 @@ import "fmt" type templateListCmd struct { SortBy []string `long:"sort-by" description:"sort by field name; must match exact header name; can be specified multiple times; format: asc:name dsc:name ascnum:name dscnum:name"` + Theme string `long:"theme" description:"for standard output, pick a theme: default|nocolor|frame|box"` + NoNotes bool `long:"no-notes" description:"for standard output, do not print extra notes below the tables"` Json bool `short:"j" long:"json" description:"Provide output in json format"` JsonPretty bool `short:"p" long:"pretty" description:"Provide json output with line-feeds and indentations"` Pager bool `long:"pager" description:"set to enable vertical and horizontal pager"` @@ -15,7 +17,7 @@ func (c *templateListCmd) Execute(args []string) error { if earlyProcess(args) { return nil } - l, err := b.TemplateListFull(c.Json, c.Pager, c.JsonPretty, c.SortBy, c.RenderType) + l, err := b.TemplateListFull(c.Json, c.Pager, c.JsonPretty, c.SortBy, c.RenderType, c.Theme, c.NoNotes) if err != nil { return err }