Merge "Implement cluster list command"

This commit is contained in:
Zuul 2021-02-10 07:11:37 +00:00 committed by Gerrit Code Review
commit 77268cd1d0
9 changed files with 246 additions and 7 deletions

View File

@ -44,6 +44,7 @@ func NewClusterCommand(cfgFactory config.Factory) *cobra.Command {
clusterRootCmd.AddCommand(resetsatoken.NewResetCommand(cfgFactory))
clusterRootCmd.AddCommand(checkexpiration.NewCheckCommand(cfgFactory))
clusterRootCmd.AddCommand(NewGetKubeconfigCommand(cfgFactory))
clusterRootCmd.AddCommand(NewListCommand(cfgFactory))
return clusterRootCmd
}

52
cmd/cluster/list.go Executable file
View File

@ -0,0 +1,52 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster
import (
"github.com/spf13/cobra"
"opendev.org/airship/airshipctl/pkg/config"
"opendev.org/airship/airshipctl/pkg/phase"
)
const (
listShort = "Retrieve the list of defined clusters"
listExample = `
# Retrieve cluster list
airshipctl cluster list --airshipconf /tmp/airconfig
`
)
// NewListCommand creates a command which retrieves list of clusters
func NewListCommand(cfgFactory config.Factory) *cobra.Command {
o := &phase.ClusterListCommand{Factory: cfgFactory}
cmd := &cobra.Command{
Use: "list",
Short: listShort,
Example: listExample[1:],
RunE: listRunE(o),
}
return cmd
}
// listRunE returns a function to cobra command to be executed in runtime
func listRunE(o *phase.ClusterListCommand) func(
cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
o.Writer = cmd.OutOrStdout()
return o.RunE()
}
}

35
cmd/cluster/list_test.go Executable file
View File

@ -0,0 +1,35 @@
/*
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cluster_test
import (
"testing"
"opendev.org/airship/airshipctl/cmd/cluster"
"opendev.org/airship/airshipctl/testutil"
)
func TestNewListCommand(t *testing.T) {
tests := []*testutil.CmdTest{
{
Name: "cluster-list-cmd-with-help",
CmdLine: "--help",
Cmd: cluster.NewListCommand(nil),
},
}
for _, testcase := range tests {
testutil.RunTest(t, testcase)
}
}

View File

@ -9,6 +9,7 @@ Available Commands:
get-kubeconfig Retrieve kubeconfig for a desired cluster
help Help about any command
init Deploy cluster-api provider components
list Retrieve the list of defined clusters
move Move Cluster API objects, provider specific objects and all dependencies to the target cluster
rotate-sa-token Rotate tokens of Service Accounts
status Retrieve statuses of deployed cluster components

View File

@ -0,0 +1,12 @@
Retrieve the list of defined clusters
Usage:
list [flags]
Examples:
# Retrieve cluster list
airshipctl cluster list --airshipconf /tmp/airconfig
Flags:
-h, --help help for list

View File

@ -27,6 +27,7 @@ such as getting status and deploying initial infrastructure.
* [airshipctl cluster check-certificate-expiration](airshipctl_cluster_check-certificate-expiration.md) - Check for expiring TLS certificates, secrets and kubeconfigs in the kubernetes cluster
* [airshipctl cluster get-kubeconfig](airshipctl_cluster_get-kubeconfig.md) - Retrieve kubeconfig for a desired cluster
* [airshipctl cluster init](airshipctl_cluster_init.md) - Deploy cluster-api provider components
* [airshipctl cluster list](airshipctl_cluster_list.md) - Retrieve the list of defined clusters
* [airshipctl cluster move](airshipctl_cluster_move.md) - Move Cluster API objects, provider specific objects and all dependencies to the target cluster
* [airshipctl cluster rotate-sa-token](airshipctl_cluster_rotate-sa-token.md) - Rotate tokens of Service Accounts
* [airshipctl cluster status](airshipctl_cluster_status.md) - Retrieve statuses of deployed cluster components

View File

@ -0,0 +1,37 @@
## airshipctl cluster list
Retrieve the list of defined clusters
### Synopsis
Retrieve the list of defined clusters
```
airshipctl cluster list [flags]
```
### Examples
```
# Retrieve cluster list
airshipctl cluster list --airshipconf /tmp/airconfig
```
### Options
```
-h, --help help for list
```
### Options inherited from parent commands
```
--airshipconf string Path to file for airshipctl configuration. (default "$HOME/.airship/config")
--debug enable verbose output
```
### SEE ALSO
* [airshipctl cluster](airshipctl_cluster.md) - Manage Kubernetes clusters

View File

@ -244,3 +244,33 @@ func (c *PlanRunCommand) RunE() error {
}
return plan.Run(ifc.RunOptions{DryRun: c.Options.DryRun, Timeout: c.Options.Timeout, Progress: c.Options.Progress})
}
// ClusterListCommand options for cluster list command
type ClusterListCommand struct {
Factory config.Factory
Writer io.Writer
}
// RunE executes cluster list command
func (c *ClusterListCommand) RunE() error {
cfg, err := c.Factory()
if err != nil {
return err
}
helper, err := NewHelper(cfg)
if err != nil {
return err
}
clusterMap, err := helper.ClusterMap()
if err != nil {
return err
}
clusterList := clusterMap.AllClusters()
for _, clusterName := range clusterList {
if _, err := c.Writer.Write([]byte(clusterName + "\n")); err != nil {
return err
}
}
return nil
}

View File

@ -28,9 +28,10 @@ import (
)
const (
testFactoryErr = "test config error"
testNewHelperErr = "Missing configuration"
testNoBundlePath = "no such file or directory"
testFactoryErr = "test config error"
testNewHelperErr = "Missing configuration"
testNoBundlePath = "no such file or directory"
defaultCurrentContext = "context"
)
func TestRunCommand(t *testing.T) {
@ -73,7 +74,7 @@ func TestRunCommand(t *testing.T) {
},
},
}
conf.CurrentContext = "context"
conf.CurrentContext = defaultCurrentContext
conf.Contexts = map[string]*config.Context{
"context": {
Manifest: "manifest",
@ -143,7 +144,7 @@ func TestListCommand(t *testing.T) {
},
},
}
conf.CurrentContext = "context"
conf.CurrentContext = defaultCurrentContext
conf.Contexts = map[string]*config.Context{
"context": {
Manifest: "manifest",
@ -211,7 +212,7 @@ func TestTreeCommand(t *testing.T) {
},
},
}
conf.CurrentContext = "context"
conf.CurrentContext = defaultCurrentContext
conf.Contexts = map[string]*config.Context{
"context": {
Manifest: "manifest",
@ -334,7 +335,7 @@ func TestPlanRunCommand(t *testing.T) {
},
},
}
conf.CurrentContext = "context"
conf.CurrentContext = defaultCurrentContext
conf.Contexts = map[string]*config.Context{
"context": {
Manifest: "manifest",
@ -367,3 +368,72 @@ func TestPlanRunCommand(t *testing.T) {
})
}
}
func TestClusterListCommand_RunE(t *testing.T) {
testErr := fmt.Errorf(testFactoryErr)
testCases := []struct {
name string
factory config.Factory
expectedErr string
}{
{
name: "Error config factory",
factory: func() (*config.Config, error) {
return nil, testErr
},
expectedErr: testFactoryErr,
},
{
name: "Error new helper",
factory: func() (*config.Config, error) {
return &config.Config{
CurrentContext: "does not exist",
Contexts: make(map[string]*config.Context),
}, nil
},
expectedErr: "Missing configuration: Context with name 'does not exist'",
},
{
name: "No error",
factory: func() (*config.Config, error) {
conf := config.NewConfig()
conf.Manifests = map[string]*config.Manifest{
"manifest": {
MetadataPath: "metadata.yaml",
TargetPath: "testdata",
PhaseRepositoryName: config.DefaultTestPhaseRepo,
Repositories: map[string]*config.Repository{
config.DefaultTestPhaseRepo: {
URLString: "",
},
},
},
}
conf.CurrentContext = defaultCurrentContext
conf.Contexts = map[string]*config.Context{
"context": {
Manifest: "manifest",
},
}
return conf, nil
},
expectedErr: "",
},
}
for _, tc := range testCases {
tt := tc
t.Run(tt.name, func(t *testing.T) {
cmd := phase.ClusterListCommand{
Factory: tt.factory,
Writer: bytes.NewBuffer(nil),
}
err := cmd.RunE()
if tt.expectedErr != "" {
require.Error(t, err)
assert.Equal(t, tt.expectedErr, err.Error())
} else {
assert.NoError(t, err)
}
})
}
}