From 24a0bda24781f7f7a5e94347b08a4ef89dcfbbeb Mon Sep 17 00:00:00 2001 From: iwilltry42 Date: Thu, 24 Oct 2019 14:57:15 +0200 Subject: [PATCH] init get kubeconfig --- cmd/get/getKubeconfig.go | 28 +++++++++--- go.mod | 2 +- pkg/cluster/kubeconfig.go | 62 ++++++++++++++++++++++++--- pkg/runtimes/containerd/kubeconfig.go | 6 ++- pkg/runtimes/docker/kubeconfig.go | 22 +++++++--- pkg/runtimes/runtime.go | 3 +- 6 files changed, 103 insertions(+), 20 deletions(-) diff --git a/cmd/get/getKubeconfig.go b/cmd/get/getKubeconfig.go index 08e9103c..ce9d45fd 100644 --- a/cmd/get/getKubeconfig.go +++ b/cmd/get/getKubeconfig.go @@ -22,6 +22,8 @@ THE SOFTWARE. package get import ( + "fmt" + "github.com/rancher/k3d/pkg/cluster" "github.com/rancher/k3d/pkg/runtimes" k3d "github.com/rancher/k3d/pkg/types" @@ -40,18 +42,27 @@ func NewCmdGetKubeconfig() *cobra.Command { Long: `Get kubeconfig.`, Run: func(cmd *cobra.Command, args []string) { log.Debugln("get kubeconfig called") - rt, c := parseGetKubeconfigCmd(cmd, args) - cluster.GetKubeconfig(rt, c) + rt, c, path := parseGetKubeconfigCmd(cmd, args) + kubeconfigpath, err := cluster.GetKubeconfigPath(rt, c, path) + if err != nil { + log.Fatalln(err) + } + + // only print kubeconfig file path if output is not stdout ("-") + if path != "-" { + fmt.Println(kubeconfigpath) + } }, } - // add subcommands + // add flags + cmd.Flags().StringP("output", "o", "", "Define output.") // done return cmd } -func parseGetKubeconfigCmd(cmd *cobra.Command, args []string) (runtimes.Runtime, *k3d.Cluster) { +func parseGetKubeconfigCmd(cmd *cobra.Command, args []string) (runtimes.Runtime, *k3d.Cluster, string) { // --runtime rt, err := cmd.Flags().GetString("runtime") if err != nil { @@ -61,5 +72,12 @@ func parseGetKubeconfigCmd(cmd *cobra.Command, args []string) (runtimes.Runtime, if err != nil { log.Fatalln(err) } - return runtime, &k3d.Cluster{Name: args[0]} // TODO: validate first? + + // --output + output, err := cmd.Flags().GetString("output") + if err != nil { + log.Fatalln("No output specified") + } + + return runtime, &k3d.Cluster{Name: args[0]}, output // TODO: validate first } diff --git a/go.mod b/go.mod index 0b2c66db..76f4ccd8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/rancher/k3d -go 1.12 +go 1.13 require ( github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect diff --git a/pkg/cluster/kubeconfig.go b/pkg/cluster/kubeconfig.go index ca0ea1c1..3bc4d142 100644 --- a/pkg/cluster/kubeconfig.go +++ b/pkg/cluster/kubeconfig.go @@ -22,21 +22,73 @@ THE SOFTWARE. package cluster import ( + "bytes" + "io/ioutil" + "os" + "github.com/rancher/k3d/pkg/runtimes" k3d "github.com/rancher/k3d/pkg/types" log "github.com/sirupsen/logrus" ) // GetKubeconfig grabs the kubeconfig file from /output from a master node container and puts it into a local directory -func GetKubeconfig(runtime runtimes.Runtime, cluster *k3d.Cluster) error { +func GetKubeconfig(runtime runtimes.Runtime, cluster *k3d.Cluster) ([]byte, error) { masterNodes, err := runtime.GetNodesByLabel(map[string]string{"k3d.cluster": cluster.Name, "k3d.role": string(k3d.MasterRole)}) if err != nil { log.Errorln("Failed to get masternodes") - return err + return nil, err } - if err := runtime.GetKubeconfig(masterNodes[0]); err != nil { + reader, err := runtime.GetKubeconfig(masterNodes[0]) + if err != nil { log.Errorf("Failed to get kubeconfig from node '%s'", masterNodes[0].Name) - return err + return nil, err } - return nil + defer reader.Close() + + readBytes, err := ioutil.ReadAll(reader) + if err != nil { + log.Errorln("Couldn't read kubeconfig file") + return nil, err + } + + // write to file, skipping the first 512 bytes which contain file metadata + // and trimming any NULL characters + trimBytes := bytes.Trim(readBytes[512:], "\x00") + + return trimBytes, nil +} + +// GetKubeconfigPath uses GetKubeConfig to grab the kubeconfig from the cluster master node, writes it to a file and outputs the path +func GetKubeconfigPath(runtime runtimes.Runtime, cluster *k3d.Cluster, path string) (string, error) { + var output *os.File + defer output.Close() + var err error + + kubeconfigBytes, err := GetKubeconfig(runtime, cluster) + if err != nil { + log.Errorln("Failed to get kubeconfig") + return "", err + } + + if path == "-" { + output = os.Stdout + } else { + if path == "" { + path = "/tmp/test.yaml" // TODO: set proper default + } + output, err = os.Create(path) + if err != nil { + log.Errorf("Failed to create file '%s'", path) + return "", err + } + } + + _, err = output.Write(kubeconfigBytes) + if err != nil { + log.Errorf("Failed to write to file '%s'", output.Name()) + return "", err + } + + return output.Name(), nil + } diff --git a/pkg/runtimes/containerd/kubeconfig.go b/pkg/runtimes/containerd/kubeconfig.go index 2c662506..0e79b2c3 100644 --- a/pkg/runtimes/containerd/kubeconfig.go +++ b/pkg/runtimes/containerd/kubeconfig.go @@ -23,10 +23,12 @@ THE SOFTWARE. package containerd import ( + "io" + k3d "github.com/rancher/k3d/pkg/types" ) // GetKubeconfig grabs the kubeconfig from inside a k3d node -func (d Containerd) GetKubeconfig(node *k3d.Node) error { - return nil +func (d Containerd) GetKubeconfig(node *k3d.Node) (io.ReadCloser, error) { + return nil, nil } diff --git a/pkg/runtimes/docker/kubeconfig.go b/pkg/runtimes/docker/kubeconfig.go index 6a48bbdd..fa951948 100644 --- a/pkg/runtimes/docker/kubeconfig.go +++ b/pkg/runtimes/docker/kubeconfig.go @@ -23,25 +23,35 @@ THE SOFTWARE. package docker import ( + "context" + "io" + + "github.com/docker/docker/client" k3d "github.com/rancher/k3d/pkg/types" log "github.com/sirupsen/logrus" ) // GetKubeconfig grabs the kubeconfig from inside a k3d node -func (d Docker) GetKubeconfig(node *k3d.Node) error { - /*ctx := context.Background +func (d Docker) GetKubeconfig(node *k3d.Node) (io.ReadCloser, error) { + ctx := context.Background() docker, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) if err != nil { log.Errorln("Failed to create docker client") - return err - }*/ + return nil, err + } container, err := getNodeContainer(node) if err != nil { - return err + return nil, err } log.Debugf("Container: %+v", container) - return nil + reader, _, err := docker.CopyFromContainer(ctx, container.ID, "/output/kubeconfig.yaml") + if err != nil { + log.Errorf("Failed to copy from container '%s'", container.ID) + return nil, err + } + + return reader, nil } diff --git a/pkg/runtimes/runtime.go b/pkg/runtimes/runtime.go index 1e9ac010..201fa260 100644 --- a/pkg/runtimes/runtime.go +++ b/pkg/runtimes/runtime.go @@ -23,6 +23,7 @@ package runtimes import ( "fmt" + "io" "github.com/rancher/k3d/pkg/runtimes/containerd" "github.com/rancher/k3d/pkg/runtimes/docker" @@ -41,7 +42,7 @@ type Runtime interface { DeleteNode(*k3d.Node) error GetNodesByLabel(map[string]string) ([]*k3d.Node, error) CreateNetworkIfNotPresent(name string) (string, error) - GetKubeconfig(*k3d.Node) error + GetKubeconfig(*k3d.Node) (io.ReadCloser, error) // StartContainer() error // ExecContainer() error // StopContainer() error