Get-kubeconfig return all cluster contexts

Now if we run `airshipctl cluster get-kubeconfig` without args
it will return kubeconfig for the entire site, which will have
contexts for every cluster defined in cluster map.

Relates-To: #460
Closes: #460

Change-Id: Icf1f09724a5c60ac520b1dbcbda69c3280ac4c7e
This commit is contained in:
Kostiantyn Kalynovskyi 2021-03-16 18:24:03 +00:00
parent e2d2607586
commit f24bf00d17
5 changed files with 85 additions and 13 deletions

View File

@ -24,31 +24,42 @@ import (
const ( const (
getKubeconfigLong = ` getKubeconfigLong = `
Retrieve cluster kubeconfig and print it to stdout Retrieve cluster kubeconfig and print it to stdout
If you specify clusterName, kubeconfig will have a CurrentContext set to clusterName and
will have this context defined
If you don't specify clusterName, kubeconfig will have multiple contexts for every cluster
in the airship site. Context names will correspond to cluster names. CurrentContext will be empty
` `
getKubeconfigExample = ` getKubeconfigExample = `
# Retrieve target-cluster kubeconfig # Retrieve target-cluster kubeconfig
airshipctl cluster get-kubeconfig target-cluster airshipctl cluster get-kubeconfig target-cluster
# Retrieve kubeconfig for the entire site; the kubeconfig will have context for every cluster
airshipctl cluster get-kubeconfig
` `
) )
// NewGetKubeconfigCommand creates a command which retrieves cluster kubeconfig // NewGetKubeconfigCommand creates a command which retrieves cluster kubeconfig
func NewGetKubeconfigCommand(cfgFactory config.Factory) *cobra.Command { func NewGetKubeconfigCommand(cfgFactory config.Factory) *cobra.Command {
opts := &cluster.GetKubeconfigCommand{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "get-kubeconfig [cluster_name]", Use: "get-kubeconfig [clusterName]",
Short: "Retrieve kubeconfig for a desired cluster", Short: "Retrieve kubeconfig for a desired cluster",
Long: getKubeconfigLong[1:], Long: getKubeconfigLong[1:],
Args: GetKubeconfArgs(opts),
Example: getKubeconfigExample[1:], Example: getKubeconfigExample[1:],
Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error {
RunE: getKubeconfigRunE(cfgFactory), return opts.RunE(cfgFactory, cmd.OutOrStdout())
},
} }
return cmd return cmd
} }
// getKubeconfigRunE returns a function to cobra command to be executed in runtime // GetKubeconfArgs extracts one or less arguments from command line, and saves it as name
func getKubeconfigRunE(cfgFactory config.Factory) func( func GetKubeconfArgs(opts *cluster.GetKubeconfigCommand) cobra.PositionalArgs {
cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error {
return cluster.GetKubeconfig(cfgFactory, args[0], cmd.OutOrStdout()) if len(args) == 1 {
opts.ClusterName = args[0]
}
return cobra.MaximumNArgs(1)(cmd, args)
} }
} }

View File

@ -17,7 +17,11 @@ package cluster_test
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"opendev.org/airship/airshipctl/cmd/cluster" "opendev.org/airship/airshipctl/cmd/cluster"
pkgcluster "opendev.org/airship/airshipctl/pkg/cluster"
"opendev.org/airship/airshipctl/testutil" "opendev.org/airship/airshipctl/testutil"
) )
@ -33,3 +37,41 @@ func TestNewKubeConfigCommandCmd(t *testing.T) {
testutil.RunTest(t, testcase) testutil.RunTest(t, testcase)
} }
} }
func TestGetKubeconfArgs(t *testing.T) {
tests := []struct {
name string
args []string
expectedErrStr string
expectedClusterName string
}{
{
name: "success one cluster specified",
args: []string{"cluster01"},
expectedClusterName: "cluster01",
},
{
name: "success no cluster specified",
},
{
name: "error two cluster specified",
expectedErrStr: "accepts at most 1 arg(s)",
args: []string{"cluster01", "cluster02"},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
cmd := &pkgcluster.GetKubeconfigCommand{}
args := cluster.GetKubeconfArgs(cmd)
err := args(cluster.NewGetKubeconfigCommand(nil), tt.args)
if tt.expectedErrStr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedErrStr)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expectedClusterName, cmd.ClusterName)
}
})
}
}

View File

@ -1,12 +1,19 @@
Retrieve cluster kubeconfig and print it to stdout Retrieve cluster kubeconfig and print it to stdout
If you specify clusterName, kubeconfig will have a CurrentContext set to clusterName and
will have this context defined
If you don't specify clusterName, kubeconfig will have multiple contexts for every cluster
in the airship site. Context names will correspond to cluster names. CurrentContext will be empty
Usage: Usage:
get-kubeconfig [cluster_name] [flags] get-kubeconfig [clusterName] [flags]
Examples: Examples:
# Retrieve target-cluster kubeconfig # Retrieve target-cluster kubeconfig
airshipctl cluster get-kubeconfig target-cluster airshipctl cluster get-kubeconfig target-cluster
# Retrieve kubeconfig for the entire site; the kubeconfig will have context for every cluster
airshipctl cluster get-kubeconfig
Flags: Flags:
-h, --help help for get-kubeconfig -h, --help help for get-kubeconfig

View File

@ -5,10 +5,14 @@ Retrieve kubeconfig for a desired cluster
### Synopsis ### Synopsis
Retrieve cluster kubeconfig and print it to stdout Retrieve cluster kubeconfig and print it to stdout
If you specify clusterName, kubeconfig will have a CurrentContext set to clusterName and
will have this context defined
If you don't specify clusterName, kubeconfig will have multiple contexts for every cluster
in the airship site. Context names will correspond to cluster names. CurrentContext will be empty
``` ```
airshipctl cluster get-kubeconfig [cluster_name] [flags] airshipctl cluster get-kubeconfig [clusterName] [flags]
``` ```
### Examples ### Examples
@ -17,6 +21,9 @@ airshipctl cluster get-kubeconfig [cluster_name] [flags]
# Retrieve target-cluster kubeconfig # Retrieve target-cluster kubeconfig
airshipctl cluster get-kubeconfig target-cluster airshipctl cluster get-kubeconfig target-cluster
# Retrieve kubeconfig for the entire site; the kubeconfig will have context for every cluster
airshipctl cluster get-kubeconfig
``` ```
### Options ### Options

View File

@ -56,8 +56,13 @@ func StatusRunner(o StatusOptions, w io.Writer) error {
return nil return nil
} }
// GetKubeconfig creates new kubeconfig interface object from secret and prints its content to writer // GetKubeconfigCommand holds options for get kubeconfig command
func GetKubeconfig(cfgFactory config.Factory, clusterName string, writer io.Writer) error { type GetKubeconfigCommand struct {
ClusterName string
}
// RunE creates new kubeconfig interface object from secret and prints its content to writer
func (cmd *GetKubeconfigCommand) RunE(cfgFactory config.Factory, writer io.Writer) error {
cfg, err := cfgFactory() cfg, err := cfgFactory()
if err != nil { if err != nil {
return err return err
@ -87,7 +92,7 @@ func GetKubeconfig(cfgFactory config.Factory, clusterName string, writer io.Writ
WithBundle(helper.PhaseBundleRoot()). WithBundle(helper.PhaseBundleRoot()).
WithClusterctClient(client). WithClusterctClient(client).
WithClusterMap(cMap). WithClusterMap(cMap).
WithClusterName(clusterName). WithClusterName(cmd.ClusterName).
WithTempRoot(wd). WithTempRoot(wd).
Build() Build()