[Enhancement] Improved listings for nodes & registries (#439, @inercia)
This commit is contained in:
parent
d17a2aefa9
commit
c6df1448ef
@ -23,8 +23,6 @@ package node
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/liggitt/tabwriter"
|
||||
@ -37,8 +35,14 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type nodeListFlags struct {
|
||||
noHeader bool
|
||||
output string
|
||||
}
|
||||
|
||||
// NewCmdNodeList returns a new cobra command
|
||||
func NewCmdNodeList() *cobra.Command {
|
||||
nodeListFlags := nodeListFlags{}
|
||||
|
||||
// create new command
|
||||
cmd := &cobra.Command{
|
||||
@ -49,7 +53,13 @@ func NewCmdNodeList() *cobra.Command {
|
||||
Args: cobra.MinimumNArgs(0), // 0 or more; 0 = all
|
||||
ValidArgsFunction: util.ValidArgsAvailableNodes,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
nodes, headersOff := parseGetNodeCmd(cmd, args)
|
||||
nodes := []*k3d.Node{}
|
||||
for _, name := range args {
|
||||
nodes = append(nodes, &k3d.Node{
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
|
||||
var existingNodes []*k3d.Node
|
||||
if len(nodes) == 0 { // Option a) no name specified -> get all nodes
|
||||
found, err := client.NodeList(cmd.Context(), runtimes.SelectedRuntime)
|
||||
@ -66,58 +76,29 @@ func NewCmdNodeList() *cobra.Command {
|
||||
existingNodes = append(existingNodes, found)
|
||||
}
|
||||
}
|
||||
// print existing clusters
|
||||
printNodes(existingNodes, headersOff)
|
||||
|
||||
// print existing nodes
|
||||
headers := &[]string{}
|
||||
if !nodeListFlags.noHeader {
|
||||
headers = &[]string{"NAME", "ROLE", "CLUSTER", "STATUS"}
|
||||
}
|
||||
|
||||
util.PrintNodes(existingNodes, nodeListFlags.output,
|
||||
headers, util.NodePrinterFunc(func(tabwriter *tabwriter.Writer, node *k3d.Node) {
|
||||
fmt.Fprintf(tabwriter, "%s\t%s\t%s\t%s\n",
|
||||
strings.TrimPrefix(node.Name, "/"),
|
||||
string(node.Role),
|
||||
node.Labels[k3d.LabelClusterName],
|
||||
node.State.Status)
|
||||
}))
|
||||
},
|
||||
}
|
||||
|
||||
// add flags
|
||||
cmd.Flags().Bool("no-headers", false, "Disable headers")
|
||||
cmd.Flags().BoolVar(&nodeListFlags.noHeader, "no-headers", false, "Disable headers")
|
||||
cmd.Flags().StringVarP(&nodeListFlags.output, "output", "o", "", "Output format. One of: json|yaml")
|
||||
|
||||
// add subcommands
|
||||
|
||||
// done
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseGetNodeCmd(cmd *cobra.Command, args []string) ([]*k3d.Node, bool) {
|
||||
// --no-headers
|
||||
headersOff, err := cmd.Flags().GetBool("no-headers")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Args = node name
|
||||
if len(args) == 0 {
|
||||
return nil, headersOff
|
||||
}
|
||||
|
||||
nodes := []*k3d.Node{}
|
||||
for _, name := range args {
|
||||
nodes = append(nodes, &k3d.Node{Name: name})
|
||||
}
|
||||
|
||||
return nodes, headersOff
|
||||
}
|
||||
|
||||
func printNodes(nodes []*k3d.Node, headersOff bool) {
|
||||
|
||||
tabwriter := tabwriter.NewWriter(os.Stdout, 6, 4, 3, ' ', tabwriter.RememberWidths)
|
||||
defer tabwriter.Flush()
|
||||
|
||||
if !headersOff {
|
||||
headers := []string{"NAME", "ROLE", "CLUSTER", "STATUS"}
|
||||
_, err := fmt.Fprintf(tabwriter, "%s\n", strings.Join(headers, "\t"))
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to print headers")
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(nodes, func(i, j int) bool {
|
||||
return nodes[i].Name < nodes[j].Name
|
||||
})
|
||||
|
||||
for _, node := range nodes {
|
||||
fmt.Fprintf(tabwriter, "%s\t%s\t%s\t%s\n", strings.TrimPrefix(node.Name, "/"), string(node.Role), node.Labels[k3d.LabelClusterName], node.State.Status)
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/liggitt/tabwriter"
|
||||
@ -36,8 +34,15 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type registryListFlags struct {
|
||||
noHeader bool
|
||||
output string
|
||||
}
|
||||
|
||||
// NewCmdRegistryList creates a new cobra command
|
||||
func NewCmdRegistryList() *cobra.Command {
|
||||
registryListFlags := registryListFlags{}
|
||||
|
||||
// create new command
|
||||
cmd := &cobra.Command{
|
||||
Use: "list [NAME [NAME...]]",
|
||||
@ -47,8 +52,15 @@ func NewCmdRegistryList() *cobra.Command {
|
||||
Args: cobra.MinimumNArgs(0), // 0 or more; 0 = all
|
||||
ValidArgsFunction: util.ValidArgsAvailableRegistries,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
nodes, headersOff := parseRegistryListCmd(cmd, args)
|
||||
var existingNodes []*k3d.Node
|
||||
|
||||
nodes := []*k3d.Node{}
|
||||
for _, name := range args {
|
||||
nodes = append(nodes, &k3d.Node{
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
|
||||
if len(nodes) == 0 { // Option a) no name specified -> get all registries
|
||||
found, err := client.NodeList(cmd.Context(), runtimes.SelectedRuntime)
|
||||
if err != nil {
|
||||
@ -66,62 +78,35 @@ func NewCmdRegistryList() *cobra.Command {
|
||||
}
|
||||
}
|
||||
existingNodes = client.NodeFilterByRoles(existingNodes, []k3d.Role{k3d.RegistryRole}, []k3d.Role{})
|
||||
|
||||
// print existing registries
|
||||
if len(existingNodes) > 0 {
|
||||
printNodes(existingNodes, headersOff)
|
||||
headers := &[]string{}
|
||||
if !registryListFlags.noHeader {
|
||||
headers = &[]string{"NAME", "ROLE", "CLUSTER"} // TODO: add status
|
||||
}
|
||||
|
||||
util.PrintNodes(existingNodes, registryListFlags.output,
|
||||
headers, util.NodePrinterFunc(func(tabwriter *tabwriter.Writer, node *k3d.Node) {
|
||||
cluster := "*"
|
||||
if _, ok := node.Labels[k3d.LabelClusterName]; ok {
|
||||
cluster = node.Labels[k3d.LabelClusterName]
|
||||
}
|
||||
fmt.Fprintf(tabwriter, "%s\t%s\t%s\n",
|
||||
strings.TrimPrefix(node.Name, "/"),
|
||||
string(node.Role),
|
||||
cluster,
|
||||
)
|
||||
}),
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
// add flags
|
||||
cmd.Flags().Bool("no-headers", false, "Disable headers")
|
||||
cmd.Flags().BoolVar(®istryListFlags.noHeader, "no-headers", false, "Disable headers")
|
||||
cmd.Flags().StringVarP(®istryListFlags.output, "output", "o", "", "Output format. One of: json|yaml")
|
||||
|
||||
// add subcommands
|
||||
|
||||
// done
|
||||
return cmd
|
||||
}
|
||||
|
||||
func parseRegistryListCmd(cmd *cobra.Command, args []string) ([]*k3d.Node, bool) {
|
||||
// --no-headers
|
||||
headersOff, err := cmd.Flags().GetBool("no-headers")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
// Args = node name
|
||||
if len(args) == 0 {
|
||||
return nil, headersOff
|
||||
}
|
||||
|
||||
nodes := []*k3d.Node{}
|
||||
for _, name := range args {
|
||||
nodes = append(nodes, &k3d.Node{
|
||||
Name: name,
|
||||
})
|
||||
}
|
||||
|
||||
return nodes, headersOff
|
||||
}
|
||||
|
||||
func printNodes(nodes []*k3d.Node, headersOff bool) {
|
||||
|
||||
tabwriter := tabwriter.NewWriter(os.Stdout, 6, 4, 3, ' ', tabwriter.RememberWidths)
|
||||
defer tabwriter.Flush()
|
||||
|
||||
if !headersOff {
|
||||
headers := []string{"NAME", "ROLE", "CLUSTER"} // TODO: add status
|
||||
_, err := fmt.Fprintf(tabwriter, "%s\n", strings.Join(headers, "\t"))
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to print headers")
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(nodes, func(i, j int) bool {
|
||||
return nodes[i].Name < nodes[j].Name
|
||||
})
|
||||
|
||||
for _, node := range nodes {
|
||||
fmt.Fprintf(tabwriter, "%s\t%s\t%s\n", strings.TrimPrefix(node.Name, "/"), string(node.Role), node.Labels[k3d.LabelClusterName])
|
||||
}
|
||||
}
|
||||
|
89
cmd/util/listings.go
Normal file
89
cmd/util/listings.go
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
Copyright © 2020 The k3d Author(s)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
package util
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/liggitt/tabwriter"
|
||||
k3d "github.com/rancher/k3d/v4/pkg/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type NodePrinter interface {
|
||||
Print(*tabwriter.Writer, *k3d.Node)
|
||||
}
|
||||
|
||||
type NodePrinterFunc func(*tabwriter.Writer, *k3d.Node)
|
||||
|
||||
func (npf NodePrinterFunc) Print(writter *tabwriter.Writer, node *k3d.Node) {
|
||||
npf(writter, node)
|
||||
}
|
||||
|
||||
// PrintNodes prints a list of nodes, either as a table or as a JSON/YAML listing
|
||||
func PrintNodes(nodes []*k3d.Node, outputFormat string, headers *[]string, nodePrinter NodePrinter) {
|
||||
outputFormat = strings.ToLower(outputFormat)
|
||||
|
||||
tabwriter := tabwriter.NewWriter(os.Stdout, 6, 4, 3, ' ', tabwriter.RememberWidths)
|
||||
defer tabwriter.Flush()
|
||||
|
||||
if outputFormat != "json" && outputFormat != "yaml" {
|
||||
if headers != nil {
|
||||
_, err := fmt.Fprintf(tabwriter, "%s\n", strings.Join(*headers, "\t"))
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to print headers")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(nodes, func(i, j int) bool {
|
||||
return nodes[i].Name < nodes[j].Name
|
||||
})
|
||||
|
||||
if outputFormat == "json" || outputFormat == "yaml" {
|
||||
var b []byte
|
||||
var err error
|
||||
|
||||
switch outputFormat {
|
||||
case "json":
|
||||
b, err = json.Marshal(nodes)
|
||||
case "yaml":
|
||||
b, err = yaml.Marshal(nodes)
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
} else {
|
||||
for _, node := range nodes {
|
||||
if !(outputFormat == "json" || outputFormat == "yaml") {
|
||||
nodePrinter.Print(tabwriter, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user