Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpk cloud get namespaces/clusters #1322

Merged
merged 10 commits into from
May 7, 2021
1 change: 1 addition & 0 deletions src/go/rpk/pkg/cli/cmd/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func NewCloudCommand(fs afero.Fs) *cobra.Command {

command.AddCommand(cloud.NewLoginCommand(fs))
command.AddCommand(cloud.NewLogoutCommand(fs))
command.AddCommand(cloud.NewGetCommand(fs))

return command
}
81 changes: 81 additions & 0 deletions src/go/rpk/pkg/cli/cmd/cloud/clusters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2021 Vectorized, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package cloud

import (
"errors"
"io"
"strconv"

log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/config"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/ui"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/yak"
)

func NewClustersCommand(fs afero.Fs) *cobra.Command {
var (
namespaceName string
)
command := &cobra.Command{
Use: "clusters",
Short: "Get clusters in given namespace",
Long: `List clusters that you have created in your namespace in your vectorized cloud organization.`,
RunE: func(cmd *cobra.Command, args []string) error {
if namespaceName == "" {
return errors.New("please provide --namespace flag")
}
yakClient := yak.NewYakClient(config.NewVCloudConfigReaderWriter(fs))
return GetClusters(yakClient, log.StandardLogger().Out, namespaceName)
},
}

command.Flags().StringVarP(
&namespaceName,
"namespace",
"n",
"",
"Namespace name from your vectorized cloud organization",
)

return command
}

func GetClusters(
c yak.CloudApiClient, out io.Writer, namespaceName string,
) error {
clusters, err := c.GetClusters(namespaceName)
if _, ok := err.(yak.ErrLoginTokenMissing); ok {
log.Info("Please run `rpk cloud login` first. ")
return err
}

if err != nil {
return err
}

printFormattedClusters(clusters, out)
return nil
}

func printFormattedClusters(clusters []*yak.Cluster, out io.Writer) {
t := ui.NewVcloudTable(out)
t.SetHeader([]string{"id", "name", "ready"})
for _, c := range clusters {
t.Append([]string{
c.Id,
c.Name,
strconv.FormatBool(c.Ready),
})
}
t.Render()
}
67 changes: 67 additions & 0 deletions src/go/rpk/pkg/cli/cmd/cloud/clusters_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2021 Vectorized, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package cloud_test

import (
"bytes"
"errors"
"strings"
"testing"

"github.com/sirupsen/logrus"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/cli/cmd/cloud"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/yak"
)

func TestClusters(t *testing.T) {
tests := []struct {
name string
client yak.CloudApiClient
expectedOutput []string
expectedError string
}{
{
"success",
&mockYakClient{},
[]string{"notready", "false"},
"",
},
{
"not logged in",
&erroredYakClient{yak.ErrLoginTokenMissing{errors.New("inner")}},
[]string{"rpk cloud login"},
"retrieving login token",
},
{
"generic client error",
&erroredYakClient{errors.New("other error")},
[]string{},
"other error",
},
}

for _, tt := range tests {
var buf bytes.Buffer
logrus.SetOutput(&buf)
err := cloud.GetClusters(tt.client, &buf, "ns")
if len(tt.expectedOutput) > 0 {
for _, s := range tt.expectedOutput {
if !strings.Contains(buf.String(), s) {
t.Errorf("%s: expecting string %s in output %s", tt.name, s, buf.String())
}
}
}
if tt.expectedError != "" {
if err == nil || !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("%s: expecting error %s got %v", tt.name, tt.expectedError, err)
}
}
}
}
28 changes: 28 additions & 0 deletions src/go/rpk/pkg/cli/cmd/cloud/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2021 Vectorized, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package cloud

import (
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

func NewGetCommand(fs afero.Fs) *cobra.Command {
command := &cobra.Command{
Use: "get",
Short: "Get resource from Vectorized cloud",
Hidden: true,
}

command.AddCommand(NewNamespacesCommand(fs))
command.AddCommand(NewClustersCommand(fs))

return command
}
63 changes: 63 additions & 0 deletions src/go/rpk/pkg/cli/cmd/cloud/namespaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright 2021 Vectorized, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package cloud

import (
"fmt"
"io"

"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/config"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/ui"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/yak"
)

func NewNamespacesCommand(fs afero.Fs) *cobra.Command {
return &cobra.Command{
Use: "namespaces",
Aliases: []string{"ns"},
Short: "Get namespaces in your vectorized cloud",
Long: `List namespaces that you have created in your vectorized cloud organization.`,
RunE: func(cmd *cobra.Command, args []string) error {
yakClient := yak.NewYakClient(config.NewVCloudConfigReaderWriter(fs))
return GetNamespaces(yakClient, logrus.StandardLogger().Out)
},
}
}

func GetNamespaces(c yak.CloudApiClient, out io.Writer) error {
ns, err := c.GetNamespaces()
if _, ok := err.(yak.ErrLoginTokenMissing); ok {
log.Info("Please run `rpk cloud login` first. ")
return err
}
if err != nil {
return err
}

printFormatted(ns, out)
return nil
}

func printFormatted(ns []*yak.Namespace, out io.Writer) {
alenkacz marked this conversation as resolved.
Show resolved Hide resolved
t := ui.NewVcloudTable(out)
t.SetHeader([]string{"id", "name", "clusters"})
for _, n := range ns {
t.Append([]string{
n.Id,
n.Name,
fmt.Sprint(len(n.ClusterIds)),
})
}
t.Render()
}
108 changes: 108 additions & 0 deletions src/go/rpk/pkg/cli/cmd/cloud/namespaces_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2021 Vectorized, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package cloud_test

import (
"bytes"
"errors"
"strings"
"testing"

"github.com/sirupsen/logrus"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/cli/cmd/cloud"
"github.com/vectorizedio/redpanda/src/go/rpk/pkg/vcloud/yak"
)

func TestNamespaces(t *testing.T) {
tests := []struct {
name string
client yak.CloudApiClient
expectedOutput []string
expectedError string
}{
{
name: "success",
client: &mockYakClient{},
expectedOutput: []string{"test", "2"},
expectedError: "",
},
{
name: "not logged in",
client: &erroredYakClient{yak.ErrLoginTokenMissing{errors.New("inner")}},
expectedOutput: []string{"rpk cloud login"},
expectedError: "retrieving login token",
},
{
name: "generic client error",
client: &erroredYakClient{errors.New("other error")},
expectedOutput: []string{},
expectedError: "other error",
},
}

for _, tt := range tests {
var buf bytes.Buffer
logrus.SetOutput(&buf)
err := cloud.GetNamespaces(tt.client, &buf)
if len(tt.expectedOutput) > 0 {
for _, s := range tt.expectedOutput {
if !strings.Contains(buf.String(), s) {
t.Errorf("%s: expecting string %s in output %s", tt.name, s, buf.String())
}
}
}
if tt.expectedError != "" {
if err == nil || !strings.Contains(err.Error(), tt.expectedError) {
t.Errorf("%s: expecting error %s got %v", tt.name, tt.expectedError, err)
}
}
}
}

// Yak client returning fixed mocked responses
type mockYakClient struct {
}

func (yc *mockYakClient) GetNamespaces() ([]*yak.Namespace, error) {
return []*yak.Namespace{
{
Id: "test",
Name: "test",
ClusterIds: []string{"1", "2"},
},
}, nil
}

func (yc *mockYakClient) GetClusters(
namespaceName string,
) ([]*yak.Cluster, error) {
return []*yak.Cluster{
{
Id: "notready",
Name: "notready",
Ready: false,
},
}, nil
}

// Yak client returning error provided on creation
type erroredYakClient struct {
err error
}

func (yc *erroredYakClient) GetNamespaces() ([]*yak.Namespace, error) {
return nil, yc.err
}

func (yc *erroredYakClient) GetClusters(
namespaceName string,
) ([]*yak.Cluster, error) {
return nil, yc.err
}
28 changes: 28 additions & 0 deletions src/go/rpk/pkg/vcloud/ui/tables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright 2020 Vectorized, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package ui

import (
"io"

"github.com/olekukonko/tablewriter"
)

func NewVcloudTable(writer io.Writer) *tablewriter.Table {
table := tablewriter.NewWriter(writer)
table.SetBorder(false)
table.SetColumnSeparator("")
table.SetHeaderLine(false)
table.SetColWidth(80)
table.SetAutoWrapText(true)
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
return table
}
Loading