diff --git a/cmd/get/get.go b/cmd/get/get.go index e46f14f5..0ab7bd5d 100644 --- a/cmd/get/get.go +++ b/cmd/get/get.go @@ -47,6 +47,7 @@ func NewCmdGet() *cobra.Command { cmd.AddCommand(NewCmdGetCluster()) cmd.AddCommand(NewCmdGetNode()) cmd.AddCommand(NewCmdGetKubeconfig()) + cmd.AddCommand(NewCmdGetClusterToken()) // done return cmd diff --git a/cmd/get/getClusterToken.go b/cmd/get/getClusterToken.go new file mode 100644 index 00000000..006528c4 --- /dev/null +++ b/cmd/get/getClusterToken.go @@ -0,0 +1,111 @@ +/* +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 get + +import ( + "fmt" + "os" + "sort" + "strings" + + "github.com/liggitt/tabwriter" + cliutil "github.com/rancher/k3d/cmd/util" + "github.com/rancher/k3d/pkg/cluster" + "github.com/rancher/k3d/pkg/runtimes" + k3d "github.com/rancher/k3d/pkg/types" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +type clusterTokenFlags struct { + validableFlags cliutil.ValidableFlags + noHeader bool +} + +// NewCmdGetClusterToken returns a new cobra command +func NewCmdGetClusterToken() *cobra.Command { + + getClusterTokenFlags := clusterTokenFlags{} + + // create new command + cmd := &cobra.Command{ + Use: "k3stoken [CLUSTER [CLUSTER [...]] | --all]", + Short: "Get cluster token", + Long: `Get k3s cluster token.`, + Args: func(cmd *cobra.Command, args []string) error { + return cliutil.ValidateClusterNameOrAllFlag(args, getClusterTokenFlags.validableFlags) + }, + Run: func(cmd *cobra.Command, args []string) { + var clusters []*k3d.Cluster + var err error + + // generate list of clusters + if getClusterTokenFlags.validableFlags.All { + clusters, err = cluster.GetClusters(runtimes.SelectedRuntime) + if err != nil { + log.Fatalln(err) + } + } else { + for _, clusterName := range args { + retrievedCluster, err := cluster.GetCluster(&k3d.Cluster{Name: clusterName}, runtimes.SelectedRuntime) + if err != nil { + log.Fatalln(err) + } + clusters = append(clusters, retrievedCluster) + } + } + + // pretty print secret + printSecret(clusters, getClusterTokenFlags.noHeader) + }, + } + + // add flags + cmd.Flags().BoolVarP(&getClusterTokenFlags.validableFlags.All, "all", "a", false, "Get k3s token from all existing clusters") + cmd.Flags().BoolVar(&getClusterTokenFlags.noHeader, "no-headers", false, "Disable headers") + + // done + return cmd +} + +func printSecret(clusters []*k3d.Cluster, headersOff bool) { + + tabwriter := tabwriter.NewWriter(os.Stdout, 6, 4, 3, ' ', tabwriter.RememberWidths) + defer tabwriter.Flush() + + if !headersOff { + headers := []string{"CLUSTER", "SECRET"} + _, err := fmt.Fprintf(tabwriter, "%s\n", strings.Join(headers, "\t")) + if err != nil { + log.Fatalln("Failed to print headers") + } + } + + // alphabetical sort by cluster name + sort.Slice(clusters, func(i, j int) bool { + return clusters[i].Name < clusters[j].Name + }) + + for _, cluster := range clusters { + fmt.Fprintf(tabwriter, "%s\t%s\n", cluster.Name, string(cluster.Secret)) + } +} diff --git a/cmd/util/args.go b/cmd/util/args.go new file mode 100644 index 00000000..e2a7fa79 --- /dev/null +++ b/cmd/util/args.go @@ -0,0 +1,44 @@ +/* +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 ( + "fmt" +) + +// struct describe flags which could be validate thanks to this file's functions +type ValidableFlags struct { + All bool +} + +// ValidateClusterNameOrAllFlag checks, if cluster name or --all arg is set +func ValidateClusterNameOrAllFlag(args []string, flagStruct ValidableFlags) error { + + clusterNamePresent := len(args) > 0 + getAllFlagPresent := flagStruct.All + + // xor : provide cluster name or all flags + if clusterNamePresent != getAllFlagPresent { + return nil + } + return fmt.Errorf("Need to specify one or more cluster names *or* set `--all` flag") +} diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index bc913614..43056c6c 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -442,6 +442,12 @@ func populateClusterFieldsFromLabels(cluster *k3d.Cluster) error { } } + // get k3s cluster's secret + if cluster.Secret == "" { + if secretToken, ok := node.Labels[k3d.SecretLabelName]; ok { + cluster.Secret = secretToken + } + } } return nil diff --git a/tests/common.sh b/tests/common.sh index f6464e4c..7b9eb5ca 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -107,3 +107,8 @@ check_registry() { check_volume_exists() { docker volume inspect "$1" >/dev/null 2>&1 } + +check_cluster_token_exist() { + [ -n "$EXE" ] || abort "EXE is not defined" + $EXE get k3stoken "$1" >/dev/null 2>&1 +} diff --git a/tests/test_basic.sh b/tests/test_basic.sh index 1ace7ba0..bdf9b930 100755 --- a/tests/test_basic.sh +++ b/tests/test_basic.sh @@ -16,6 +16,10 @@ check_cluster_count 2 info "Checking we have access to both clusters..." check_clusters "c1" "c2" || failed "error checking cluster" +info "Check k3s token retrieval" +check_cluster_token_exist "c1" || failed "could not find cluster token c1" +check_cluster_token_exist "c2" || failed "could not find cluster token c2" + info "Deleting clusters..." $EXE delete cluster c1 || failed "could not delete the cluster c1" $EXE delete cluster c2 || failed "could not delete the cluster c2"