-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
OCM-7263 | feat: Add the ability to list KubeletConfigs for a cluster
- Loading branch information
Showing
10 changed files
with
416 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package kubeletconfig | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"os" | ||
"text/tabwriter" | ||
|
||
"github.com/spf13/cobra" | ||
|
||
"github.com/openshift/rosa/pkg/kubeletconfig" | ||
"github.com/openshift/rosa/pkg/ocm" | ||
"github.com/openshift/rosa/pkg/output" | ||
"github.com/openshift/rosa/pkg/rosa" | ||
) | ||
|
||
const ( | ||
use = "kubeletconfigs" | ||
short = "List kubeletconfigs" | ||
long = short | ||
example = ` # List the kubeletconfigs for cluster 'foo' | ||
rosa list kubeletconfig --cluster foo` | ||
alias = "kubelet-configs" | ||
) | ||
|
||
func NewListKubeletConfigsCommand() *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: use, | ||
Short: short, | ||
Long: long, | ||
Example: example, | ||
Aliases: []string{alias}, | ||
Args: cobra.NoArgs, | ||
Run: rosa.DefaultRunner(rosa.RuntimeWithOCM(), ListKubeletConfigRunner()), | ||
} | ||
|
||
output.AddFlag(cmd) | ||
ocm.AddClusterFlag(cmd) | ||
return cmd | ||
} | ||
|
||
func ListKubeletConfigRunner() rosa.CommandRunner { | ||
return func(ctx context.Context, runtime *rosa.Runtime, command *cobra.Command, args []string) error { | ||
|
||
cluster, err := runtime.OCMClient.GetCluster(runtime.GetClusterKey(), runtime.Creator) | ||
if err != nil { | ||
return err | ||
} | ||
kubeletConfigs, err := runtime.OCMClient.ListKubeletConfigs(ctx, cluster.ID()) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if output.HasFlag() { | ||
output.Print(kubeletConfigs) | ||
} else { | ||
if len(kubeletConfigs) == 0 { | ||
runtime.Reporter.Infof("There are no KubeletConfigs for cluster '%s'.", runtime.ClusterKey) | ||
return nil | ||
} | ||
|
||
writer := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0) | ||
fmt.Fprint(writer, kubeletconfig.PrintKubeletConfigsForTabularOutput(kubeletConfigs)) | ||
return writer.Flush() | ||
} | ||
|
||
return nil | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package kubeletconfig | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
func TestListKubeletConfigs(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "List KubeletConfigs Suite") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package kubeletconfig | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
. "github.com/openshift-online/ocm-sdk-go/testing" | ||
|
||
"github.com/openshift/rosa/pkg/output" | ||
. "github.com/openshift/rosa/pkg/test" | ||
) | ||
|
||
var tabularOutput = `ID NAME POD PIDS LIMIT | ||
foo testing 10000 | ||
bar testing2 20000 | ||
` | ||
|
||
var _ = Describe("List KubeletConfig Command", func() { | ||
|
||
Context("Create Command", func() { | ||
It("Creates the command correctly", func() { | ||
cmd := NewListKubeletConfigsCommand() | ||
Expect(cmd).NotTo(BeNil()) | ||
|
||
Expect(cmd.Use).To(Equal(use)) | ||
Expect(cmd.Short).To(Equal(short)) | ||
Expect(cmd.Long).To(Equal(long)) | ||
Expect(cmd.Aliases).To(ContainElements(alias)) | ||
Expect(cmd.Args).NotTo(BeNil()) | ||
Expect(cmd.Run).NotTo(BeNil()) | ||
Expect(cmd.RunE).To(BeNil()) | ||
|
||
flags := cmd.Flags() | ||
Expect(flags.Lookup("cluster")).NotTo(BeNil()) | ||
Expect(flags.Lookup("output")).NotTo(BeNil()) | ||
}) | ||
}) | ||
|
||
Context("Command Runner", func() { | ||
|
||
var t *TestingRuntime | ||
|
||
BeforeEach(func() { | ||
t = NewTestRuntime() | ||
output.SetOutput("") | ||
}) | ||
|
||
AfterEach(func() { | ||
output.SetOutput("") | ||
}) | ||
|
||
It("Returns an error if the cluster does not exist", func() { | ||
|
||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatClusterList(make([]*cmv1.Cluster, 0)))) | ||
t.SetCluster("cluster", nil) | ||
|
||
runner := ListKubeletConfigRunner() | ||
err := runner(context.Background(), t.RosaRuntime, nil, nil) | ||
Expect(err).To(HaveOccurred()) | ||
Expect(err.Error()).To( | ||
Equal("There is no cluster with identifier or name 'cluster'")) | ||
}) | ||
|
||
It("Returns an error if OCM API fails to list KubeletConfigs", func() { | ||
cluster := MockCluster(func(c *cmv1.ClusterBuilder) { | ||
c.State(cmv1.ClusterStateReady) | ||
}) | ||
|
||
t.SetCluster(cluster.Name(), cluster) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatClusterList([]*cmv1.Cluster{cluster}))) | ||
t.ApiServer.RouteToHandler( | ||
"GET", | ||
fmt.Sprintf("/api/clusters_mgmt/v1/clusters/%s/kubelet_configs", cluster.ID()), | ||
RespondWithJSON(http.StatusInternalServerError, "{}")) | ||
|
||
runner := ListKubeletConfigRunner() | ||
err := runner(context.Background(), t.RosaRuntime, nil, nil) | ||
|
||
Expect(err).NotTo(BeNil()) | ||
Expect(err.Error()).To(ContainSubstring("status is 500")) | ||
}) | ||
|
||
It("Prints message if there are no KubeletConfigs for the cluster", func() { | ||
cluster := MockCluster(func(c *cmv1.ClusterBuilder) { | ||
c.State(cmv1.ClusterStateReady) | ||
}) | ||
|
||
t.SetCluster(cluster.Name(), cluster) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatClusterList([]*cmv1.Cluster{cluster}))) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatKubeletConfigList([]*cmv1.KubeletConfig{}))) | ||
|
||
runner := ListKubeletConfigRunner() | ||
|
||
t.StdOutReader.Record() | ||
err := runner(context.Background(), t.RosaRuntime, nil, nil) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
stdOut, _ := t.StdOutReader.Read() | ||
Expect(stdOut).To(Equal("INFO: There are no KubeletConfigs for cluster 'cluster'.\n")) | ||
}) | ||
|
||
It("Prints empty json if there are no KubeletConfigs for the cluster", func() { | ||
output.SetOutput("json") | ||
cluster := MockCluster(func(c *cmv1.ClusterBuilder) { | ||
c.State(cmv1.ClusterStateReady) | ||
}) | ||
|
||
t.SetCluster(cluster.Name(), cluster) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatClusterList([]*cmv1.Cluster{cluster}))) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatKubeletConfigList([]*cmv1.KubeletConfig{}))) | ||
|
||
runner := ListKubeletConfigRunner() | ||
|
||
t.StdOutReader.Record() | ||
err := runner(context.Background(), t.RosaRuntime, nil, nil) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
stdOut, _ := t.StdOutReader.Read() | ||
Expect(stdOut).To(Equal("[]\n")) | ||
}) | ||
|
||
It("Prints empty yaml if there are no KubeletConfigs for the cluster", func() { | ||
output.SetOutput("yaml") | ||
cluster := MockCluster(func(c *cmv1.ClusterBuilder) { | ||
c.State(cmv1.ClusterStateReady) | ||
}) | ||
|
||
t.SetCluster(cluster.Name(), cluster) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatClusterList([]*cmv1.Cluster{cluster}))) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatKubeletConfigList([]*cmv1.KubeletConfig{}))) | ||
|
||
runner := ListKubeletConfigRunner() | ||
|
||
t.StdOutReader.Record() | ||
err := runner(context.Background(), t.RosaRuntime, nil, nil) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
stdOut, _ := t.StdOutReader.Read() | ||
Expect(stdOut).To(Equal("[]\n")) | ||
}) | ||
|
||
It("Prints tabular list of KubeletConfigs for the cluster", func() { | ||
cluster := MockCluster(func(c *cmv1.ClusterBuilder) { | ||
c.State(cmv1.ClusterStateReady) | ||
}) | ||
|
||
kubeletConfig := MockKubeletConfig(func(k *cmv1.KubeletConfigBuilder) { | ||
k.Name("testing").ID("foo").PodPidsLimit(10000) | ||
}) | ||
|
||
kubeletConfig2 := MockKubeletConfig(func(k *cmv1.KubeletConfigBuilder) { | ||
k.Name("testing2").ID("bar").PodPidsLimit(20000) | ||
}) | ||
|
||
t.SetCluster(cluster.Name(), cluster) | ||
t.ApiServer.AppendHandlers(RespondWithJSON(http.StatusOK, FormatClusterList([]*cmv1.Cluster{cluster}))) | ||
t.ApiServer.AppendHandlers( | ||
RespondWithJSON( | ||
http.StatusOK, FormatKubeletConfigList( | ||
[]*cmv1.KubeletConfig{kubeletConfig, kubeletConfig2}))) | ||
|
||
runner := ListKubeletConfigRunner() | ||
|
||
t.StdOutReader.Record() | ||
err := runner(context.Background(), t.RosaRuntime, nil, nil) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
stdOut, _ := t.StdOutReader.Read() | ||
Expect(stdOut).To(Equal(tabularOutput)) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package kubeletconfig | ||
|
||
import ( | ||
"fmt" | ||
|
||
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
) | ||
|
||
const emptyName = "-" | ||
|
||
func PrintKubeletConfigsForTabularOutput(configs []*cmv1.KubeletConfig) string { | ||
output := "ID\tNAME\tPOD PIDS LIMIT\n" | ||
for _, config := range configs { | ||
|
||
name := config.Name() | ||
if name == "" { | ||
name = emptyName | ||
} | ||
output += fmt.Sprintf("%s\t%s\t%d\n", config.ID(), name, config.PodPidsLimit()) | ||
} | ||
|
||
return output | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package kubeletconfig | ||
|
||
import ( | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1" | ||
|
||
. "github.com/openshift/rosa/pkg/test" | ||
) | ||
|
||
var _ = Describe("KubeletConfig Output", func() { | ||
It("Correctly Prints KubeletConfigList for Tabuluar Output", func() { | ||
|
||
kubeletConfig := MockKubeletConfig(func(k *cmv1.KubeletConfigBuilder) { | ||
k.Name("test").PodPidsLimit(10000).ID("foo") | ||
}) | ||
|
||
kubeletConfig2 := MockKubeletConfig(func(k *cmv1.KubeletConfigBuilder) { | ||
k.Name("").PodPidsLimit(20000).ID("bar") | ||
}) | ||
|
||
output := PrintKubeletConfigsForTabularOutput([]*cmv1.KubeletConfig{kubeletConfig, kubeletConfig2}) | ||
Expect(output).To(Equal("ID\tNAME\tPOD PIDS LIMIT\nfoo\ttest\t10000\nbar\t-\t20000\n")) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.