From 536b543cc2fc0ee6a4ec937745f92ec3734987fa Mon Sep 17 00:00:00 2001 From: iwilltry42 Date: Wed, 13 Nov 2019 14:58:59 +0100 Subject: [PATCH] implement get nodes --- cmd/get/getCluster.go | 1 - cmd/get/getNode.go | 85 +++++++++++++++++++++++++++++++-- pkg/cluster/node.go | 22 +++++++++ pkg/runtimes/containerd/node.go | 5 ++ pkg/runtimes/docker/node.go | 18 +++++++ pkg/runtimes/runtime.go | 1 + 6 files changed, 128 insertions(+), 4 deletions(-) diff --git a/cmd/get/getCluster.go b/cmd/get/getCluster.go index a9ed9a75..0706430a 100644 --- a/cmd/get/getCluster.go +++ b/cmd/get/getCluster.go @@ -104,7 +104,6 @@ func parseGetClusterCmd(cmd *cobra.Command, args []string) (*k3d.Cluster, runtim return cluster, runtime, headersOff } -// TODO: improve (tabular output or output similar to kubectl) func printClusters(clusters []*k3d.Cluster, headersOff bool) { tabwriter := tabwriter.NewWriter(os.Stdout, 6, 4, 3, ' ', tabwriter.RememberWidths) diff --git a/cmd/get/getNode.go b/cmd/get/getNode.go index 4b11369c..33f4fa77 100644 --- a/cmd/get/getNode.go +++ b/cmd/get/getNode.go @@ -22,6 +22,15 @@ THE SOFTWARE. package get import ( + "fmt" + "os" + "sort" + "strings" + + "github.com/liggitt/tabwriter" + "github.com/rancher/k3d/pkg/cluster" + "github.com/rancher/k3d/pkg/runtimes" + k3d "github.com/rancher/k3d/pkg/types" "github.com/spf13/cobra" log "github.com/sirupsen/logrus" @@ -32,16 +41,86 @@ func NewCmdGetNode() *cobra.Command { // create new command cmd := &cobra.Command{ - Use: "node", - Short: "Get node", - Long: `Get node.`, + Use: "node", + Short: "Get node", + Aliases: []string{"nodes"}, + Long: `Get node.`, Run: func(cmd *cobra.Command, args []string) { log.Debugln("get node called") + node, runtime, headersOff := parseGetNodeCmd(cmd, args) + var existingNodes []*k3d.Node + if node == nil { // Option a) no name specified -> get all nodes + found, err := cluster.GetNodes(runtime) + if err != nil { + log.Fatalln(err) + } + existingNodes = append(existingNodes, found...) + } else { // Option b) cluster name specified -> get specific cluster + found, err := cluster.GetNode(node, runtime) + if err != nil { + log.Fatalln(err) + } + existingNodes = append(existingNodes, found) + } + // print existing clusters + printNodes(existingNodes, headersOff) }, } + // add flags + cmd.Flags().Bool("no-headers", false, "Disable headers") + // add subcommands // done return cmd } + +func parseGetNodeCmd(cmd *cobra.Command, args []string) (*k3d.Node, runtimes.Runtime, bool) { + // --runtime + rt, err := cmd.Flags().GetString("runtime") + if err != nil { + log.Fatalln("No runtime specified") + } + runtime, err := runtimes.GetRuntime(rt) + if err != nil { + log.Fatalln(err) + } + + // --no-headers + headersOff, err := cmd.Flags().GetBool("no-headers") + if err != nil { + log.Fatalln(err) + } + + // Args = node name + if len(args) == 0 { + return nil, runtime, headersOff + } + + node := &k3d.Node{Name: args[0]} // TODO: validate name first? + + return node, runtime, 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.cluster"]) + } +} diff --git a/pkg/cluster/node.go b/pkg/cluster/node.go index 3acfd7c9..c5273872 100644 --- a/pkg/cluster/node.go +++ b/pkg/cluster/node.go @@ -135,3 +135,25 @@ func patchMasterSpec(node *k3d.Node) error { node.Ports = append(node.Ports, fmt.Sprintf("%s:%s:6443/tcp", hostIP, apiPort)) // TODO: get '6443' from defaultport variable return nil } + +// GetNodes returns a list of all existing clusters +func GetNodes(runtime k3drt.Runtime) ([]*k3d.Node, error) { + nodes, err := runtime.GetNodesByLabel(k3d.DefaultObjectLabels) + if err != nil { + log.Errorln("Failed to get nodes") + return nil, err + } + + return nodes, nil +} + +// GetNode returns an existing cluster +func GetNode(node *k3d.Node, runtime k3drt.Runtime) (*k3d.Node, error) { + // get node + node, err := runtime.GetNode(node) + if err != nil { + log.Errorf("Failed to get node '%s'", node.Name) + } + + return node, nil +} diff --git a/pkg/runtimes/containerd/node.go b/pkg/runtimes/containerd/node.go index c5dcba29..8a886448 100644 --- a/pkg/runtimes/containerd/node.go +++ b/pkg/runtimes/containerd/node.go @@ -114,3 +114,8 @@ func (d Containerd) StopNode(node *k3d.Node) error { func (d Containerd) GetNodesByLabel(labels map[string]string) ([]*k3d.Node, error) { return nil, nil } + +// GetNode tries to get a node container by its name +func (d Containerd) GetNode(node *k3d.Node) (*k3d.Node, error) { + return nil, nil +} diff --git a/pkg/runtimes/docker/node.go b/pkg/runtimes/docker/node.go index da91653c..3db3eb47 100644 --- a/pkg/runtimes/docker/node.go +++ b/pkg/runtimes/docker/node.go @@ -167,3 +167,21 @@ func getContainersByLabel(labels map[string]string) ([]types.Container, error) { } return containers, nil } + +// GetNode tries to get a node container by its name +func (d Docker) GetNode(node *k3d.Node) (*k3d.Node, error) { + container, err := getNodeContainer(node) + if err != nil { + log.Errorf("Failed to get container for node '%s'", node.Name) + return nil, err + } + + node, err = TranslateContainerToNode(container) + if err != nil { + log.Errorf("Failed to translate container for node '%s' to node object", node.Name) + return nil, err + } + + return node, nil + +} diff --git a/pkg/runtimes/runtime.go b/pkg/runtimes/runtime.go index c0b93f00..6ccdf488 100644 --- a/pkg/runtimes/runtime.go +++ b/pkg/runtimes/runtime.go @@ -41,6 +41,7 @@ type Runtime interface { CreateNode(*k3d.Node) error DeleteNode(*k3d.Node) error GetNodesByLabel(map[string]string) ([]*k3d.Node, error) + GetNode(*k3d.Node) (*k3d.Node, error) CreateNetworkIfNotPresent(name string) (string, bool, error) // @return NETWORK_NAME, EXISTS, ERROR GetKubeconfig(*k3d.Node) (io.ReadCloser, error) DeleteNetwork(ID string) error