From fb55c25ef338f8be7262d1bb7208eb1a0cf6b71b Mon Sep 17 00:00:00 2001 From: Rob Blake Date: Mon, 13 May 2024 14:06:09 +0100 Subject: [PATCH] OCM-7266 | feat: Added support for delete of KubeletConfig for HCP clusters --- cmd/create/kubeletconfig/cmd.go | 9 +- cmd/dlt/cmd.go | 5 +- cmd/dlt/kubeletconfig/cmd.go | 89 ++++++++----- cmd/dlt/kubeletconfig/cmd_test.go | 120 ++++++++++++++++++ .../kubeletconfig/kubeletconfig_suite_test.go | 13 ++ cmd/edit/kubeletconfig/cmd.go | 9 +- pkg/kubeletconfig/input.go | 49 +++++++ pkg/kubeletconfig/input_test.go | 19 +++ pkg/kubeletconfig/options.go | 18 ++- pkg/kubeletconfig/options_test.go | 20 ++- pkg/ocm/kubeletconfig.go | 34 ++++- pkg/ocm/kubeletconfig_test.go | 31 ++++- 12 files changed, 356 insertions(+), 60 deletions(-) create mode 100644 cmd/dlt/kubeletconfig/cmd_test.go create mode 100644 cmd/dlt/kubeletconfig/kubeletconfig_suite_test.go create mode 100644 pkg/kubeletconfig/input.go create mode 100644 pkg/kubeletconfig/input_test.go diff --git a/cmd/create/kubeletconfig/cmd.go b/cmd/create/kubeletconfig/cmd.go index 88ac6e85e4..fe033cf738 100644 --- a/cmd/create/kubeletconfig/cmd.go +++ b/cmd/create/kubeletconfig/cmd.go @@ -24,7 +24,6 @@ import ( "github.com/spf13/cobra" "github.com/openshift/rosa/pkg/interactive" - "github.com/openshift/rosa/pkg/interactive/confirm" . "github.com/openshift/rosa/pkg/kubeletconfig" "github.com/openshift/rosa/pkg/ocm" "github.com/openshift/rosa/pkg/rosa" @@ -52,7 +51,7 @@ func NewCreateKubeletConfigCommand() *cobra.Command { Args: cobra.NoArgs, } - options.AddFlagsToCommand(cmd) + options.AddAllFlags(cmd) ocm.AddClusterFlag(cmd) interactive.AddFlag(cmd.Flags()) return cmd @@ -97,11 +96,7 @@ func CreateKubeletConfigRunner(options *KubeletConfigOptions) rosa.CommandRunner if !cluster.Hypershift().Enabled() { // Creating a KubeletConfig for a classic cluster must prompt the user, as the changes apply // immediately and cause reboots of the worker nodes in their cluster - prompt := fmt.Sprintf("Creating a KubeletConfig for cluster '%s' will cause all non-Control Plane "+ - "nodes to reboot. This may cause outages to your applications. Do you wish to continue?", clusterKey) - - if !confirm.ConfirmRaw(prompt) { - r.Reporter.Infof("Creation of KubeletConfig for cluster '%s' aborted.", clusterKey) + if !PromptUserToAcceptWorkerNodeReboot(OperationCreate, r) { return nil } } diff --git a/cmd/dlt/cmd.go b/cmd/dlt/cmd.go index 4eb589ff72..ae9dd809ba 100644 --- a/cmd/dlt/cmd.go +++ b/cmd/dlt/cmd.go @@ -66,7 +66,8 @@ func init() { Cmd.AddCommand(tuningconfigs.Cmd) Cmd.AddCommand(dnsdomains.Cmd) Cmd.AddCommand(autoscaler.Cmd) - Cmd.AddCommand(kubeletconfig.Cmd) + kubeletconfig := kubeletconfig.NewDeleteKubeletConfigCommand() + Cmd.AddCommand(kubeletconfig) Cmd.AddCommand(externalauthprovider.Cmd) flags := Cmd.PersistentFlags() @@ -80,7 +81,7 @@ func init() { oidcprovider.Cmd, upgrade.Cmd, admin.Cmd, service.Cmd, autoscaler.Cmd, idp.Cmd, cluster.Cmd, dnsdomains.Cmd, externalauthprovider.Cmd, - kubeletconfig.Cmd, machinepool.Cmd, tuningconfigs.Cmd, + kubeletconfig, machinepool.Cmd, tuningconfigs.Cmd, } arguments.MarkRegionDeprecated(Cmd, globallyAvailableCommands) } diff --git a/cmd/dlt/kubeletconfig/cmd.go b/cmd/dlt/kubeletconfig/cmd.go index 113ae281f1..888066c79a 100644 --- a/cmd/dlt/kubeletconfig/cmd.go +++ b/cmd/dlt/kubeletconfig/cmd.go @@ -17,55 +17,80 @@ limitations under the License. package kubeletconfig import ( + "context" "fmt" - "os" "github.com/spf13/cobra" "github.com/openshift/rosa/pkg/interactive/confirm" + . "github.com/openshift/rosa/pkg/kubeletconfig" "github.com/openshift/rosa/pkg/ocm" "github.com/openshift/rosa/pkg/rosa" ) -var Cmd = &cobra.Command{ - Use: "kubeletconfig", - Aliases: []string{"kubelet-config"}, - Short: "Delete the custom kubeletconfig for a cluster", - Long: "Delete the custom kubeletconfig for a cluster", - Example: ` # Delete the custom kubeletconfig for cluster 'foo' - rosa delete kubeletconfig --cluster foo`, - Run: run, - Args: cobra.NoArgs, -} +const ( + use = "kubeletconfig" + short = "Delete a kubeletconfig from a cluster" + long = short + example = ` # Delete the KubeletConfig for ROSA Classic cluster 'foo' + rosa delete kubeletconfig --cluster foo + # Delete the KubeletConfig named 'bar' from cluster 'foo' + rosa delete kubeletconfig --cluster foo --name bar +` +) -func init() { - ocm.AddClusterFlag(Cmd) - confirm.AddFlag(Cmd.Flags()) -} +var aliases = []string{"kubelet-config"} -func run(_ *cobra.Command, _ []string) { - r := rosa.NewRuntime().WithOCM() - defer r.Cleanup() +func NewDeleteKubeletConfigCommand() *cobra.Command { - clusterKey := r.GetClusterKey() - cluster := r.FetchCluster() + options := NewKubeletConfigOptions() - r.Reporter.Debugf("Deleting KubeletConfig for cluster '%s'", clusterKey) + var cmd = &cobra.Command{ + Use: use, + Aliases: aliases, + Short: short, + Long: long, + Example: example, + Run: rosa.DefaultRunner(rosa.RuntimeWithOCM(), DeleteKubeletConfigRunner(options)), + Args: cobra.NoArgs, + } + ocm.AddClusterFlag(cmd) + confirm.AddFlag(cmd.Flags()) + options.AddNameFlag(cmd) + return cmd +} - prompt := fmt.Sprintf("Deleting the custom KubeletConfig for cluster '%s' will cause all non-Control Plane "+ - "nodes to reboot. This may cause outages to your applications. Do you wish to continue?", clusterKey) +func DeleteKubeletConfigRunner(options *KubeletConfigOptions) rosa.CommandRunner { + return func(ctx context.Context, r *rosa.Runtime, command *cobra.Command, args []string) error { - if confirm.ConfirmRaw(prompt) { + cluster, err := r.OCMClient.GetCluster(r.GetClusterKey(), r.Creator) + if err != nil { + return err + } + + if !cluster.Hypershift().Enabled() { + if !PromptUserToAcceptWorkerNodeReboot(OperationDelete, r) { + return nil + } + } + + if cluster.Hypershift().Enabled() { + options.Name, err = PromptForName(options.Name) + if err != nil { + return err + } + options.ValidateForHypershift() + err = r.OCMClient.DeleteKubeletConfigByName(ctx, cluster.ID(), options.Name) + } else { + err = r.OCMClient.DeleteKubeletConfig(ctx, cluster.ID()) + } - err := r.OCMClient.DeleteKubeletConfig(cluster.ID()) if err != nil { - r.Reporter.Errorf("Failed to delete custom KubeletConfig for cluster '%s': '%s'", - clusterKey, err) - os.Exit(1) + return fmt.Errorf("Failed to delete KubeletConfig for cluster '%s': '%s'", + r.GetClusterKey(), err) } - r.Reporter.Infof("Successfully deleted custom KubeletConfig for cluster '%s'", clusterKey) - os.Exit(0) - } - r.Reporter.Infof("Delete of custom KubeletConfig for cluster '%s' aborted.", clusterKey) + r.Reporter.Infof("Successfully deleted KubeletConfig for cluster '%s'", r.GetClusterKey()) + return nil + } } diff --git a/cmd/dlt/kubeletconfig/cmd_test.go b/cmd/dlt/kubeletconfig/cmd_test.go new file mode 100644 index 0000000000..c01f6b88ff --- /dev/null +++ b/cmd/dlt/kubeletconfig/cmd_test.go @@ -0,0 +1,120 @@ +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/kubeletconfig" + "github.com/openshift/rosa/pkg/output" + . "github.com/openshift/rosa/pkg/test" +) + +var _ = Describe("delete kubeletconfig", func() { + + It("Correctly builds the command", func() { + cmd := NewDeleteKubeletConfigCommand() + Expect(cmd).NotTo(BeNil()) + + Expect(cmd.Use).To(Equal(use)) + Expect(cmd.Short).To(Equal(short)) + Expect(cmd.Long).To(Equal(long)) + Expect(cmd.Args).NotTo(BeNil()) + Expect(cmd.Run).NotTo(BeNil()) + + Expect(cmd.Flags().Lookup("cluster")).NotTo(BeNil()) + Expect(cmd.Flags().Lookup(PodPidsLimitOption)).To(BeNil()) + Expect(cmd.Flags().Lookup(NameOption)).NotTo(BeNil()) + }) + + Context("Delete KubeletConfig 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 := DeleteKubeletConfigRunner(NewKubeletConfigOptions()) + 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("Deletes KubeletConfig by name for HCP Clusters", func() { + + cluster := MockCluster(func(c *cmv1.ClusterBuilder) { + c.State(cmv1.ClusterStateReady) + b := cmv1.HypershiftBuilder{} + b.Enabled(true) + c.Hypershift(&b) + }) + + kubeletConfig := MockKubeletConfig(func(k *cmv1.KubeletConfigBuilder) { + k.ID("testing").PodPidsLimit(5000).Name("testing") + }) + + t.ApiServer.AppendHandlers( + RespondWithJSON( + http.StatusOK, FormatClusterList([]*cmv1.Cluster{cluster}))) + t.ApiServer.AppendHandlers( + RespondWithJSON(http.StatusOK, FormatKubeletConfigList([]*cmv1.KubeletConfig{kubeletConfig}))) + t.ApiServer.RouteToHandler(http.MethodDelete, + fmt.Sprintf("/api/clusters_mgmt/v1/clusters/%s/kubelet_configs/%s", cluster.ID(), kubeletConfig.ID()), + RespondWithJSON(http.StatusOK, FormatResource(kubeletConfig))) + t.SetCluster("cluster", cluster) + + options := NewKubeletConfigOptions() + options.Name = "testing" + + runner := DeleteKubeletConfigRunner(options) + t.StdOutReader.Record() + + err := runner(context.Background(), t.RosaRuntime, nil, nil) + Expect(err).NotTo(HaveOccurred()) + + stdOut, _ := t.StdOutReader.Read() + Expect(stdOut).To(Equal("INFO: Successfully deleted KubeletConfig for cluster 'cluster'\n")) + }) + + It("Fails to delete KubeletConfig by name for HCP Clusters if the KubeletConfig does not exist", func() { + cluster := MockCluster(func(c *cmv1.ClusterBuilder) { + c.State(cmv1.ClusterStateReady) + b := cmv1.HypershiftBuilder{} + b.Enabled(true) + c.Hypershift(&b) + }) + + t.ApiServer.AppendHandlers( + RespondWithJSON( + http.StatusOK, FormatClusterList([]*cmv1.Cluster{cluster}))) + t.ApiServer.AppendHandlers( + RespondWithJSON(http.StatusOK, FormatKubeletConfigList([]*cmv1.KubeletConfig{}))) + t.SetCluster("cluster", cluster) + + options := NewKubeletConfigOptions() + options.Name = "testing" + + runner := DeleteKubeletConfigRunner(options) + + err := runner(context.Background(), t.RosaRuntime, nil, nil) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("Failed to delete KubeletConfig for cluster 'cluster'")) + }) + }) +}) diff --git a/cmd/dlt/kubeletconfig/kubeletconfig_suite_test.go b/cmd/dlt/kubeletconfig/kubeletconfig_suite_test.go new file mode 100644 index 0000000000..8e03e357fa --- /dev/null +++ b/cmd/dlt/kubeletconfig/kubeletconfig_suite_test.go @@ -0,0 +1,13 @@ +package kubeletconfig + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestDeleteKubeletConfig(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Delete KubeletConfig Suite") +} diff --git a/cmd/edit/kubeletconfig/cmd.go b/cmd/edit/kubeletconfig/cmd.go index b7ef2094d3..bbb2839632 100644 --- a/cmd/edit/kubeletconfig/cmd.go +++ b/cmd/edit/kubeletconfig/cmd.go @@ -24,7 +24,6 @@ import ( "github.com/spf13/cobra" "github.com/openshift/rosa/pkg/interactive" - "github.com/openshift/rosa/pkg/interactive/confirm" . "github.com/openshift/rosa/pkg/kubeletconfig" "github.com/openshift/rosa/pkg/ocm" "github.com/openshift/rosa/pkg/rosa" @@ -63,7 +62,7 @@ func NewEditKubeletConfigCommand() *cobra.Command { ocm.AddClusterFlag(cmd) interactive.AddFlag(flags) - options.AddFlagsToCommand(cmd) + options.AddAllFlags(cmd) return cmd } @@ -109,11 +108,7 @@ func EditKubeletConfigRunner(options *KubeletConfigOptions) rosa.CommandRunner { if !cluster.Hypershift().Enabled() { // Classic clusters must prompt the user as edit will cause all worker nodes to reboot - prompt := fmt.Sprintf("Updating the custom KubeletConfig for cluster '%s' will cause all non-Control Plane "+ - "nodes to reboot. This may cause outages to your applications. Do you wish to continue?", r.GetClusterKey()) - - if !confirm.ConfirmRaw(prompt) { - r.Reporter.Infof("Update of custom KubeletConfig for cluster '%s' aborted.", r.GetClusterKey()) + if !PromptUserToAcceptWorkerNodeReboot(OperationEdit, r) { return nil } } diff --git a/pkg/kubeletconfig/input.go b/pkg/kubeletconfig/input.go new file mode 100644 index 0000000000..fd0ce086ae --- /dev/null +++ b/pkg/kubeletconfig/input.go @@ -0,0 +1,49 @@ +package kubeletconfig + +import ( + "fmt" + + "github.com/openshift/rosa/pkg/interactive/confirm" + "github.com/openshift/rosa/pkg/rosa" +) + +const ( + promptMessage = "%s the KubeletConfig for cluster '%s' will cause all non-Control Plane " + + "nodes to reboot. This may cause outages to your applications. Do you wish to continue?" + abortMessage = "%s of KubeletConfig for cluster '%s' aborted." + OperationDelete KubeletOperation = "delete" + OperationEdit KubeletOperation = "edit" + OperationCreate KubeletOperation = "create" +) + +type KubeletOperation string + +var ( + singularTense = map[KubeletOperation]string{ + OperationEdit: "Edit", + OperationDelete: "Delete", + OperationCreate: "Create", + } + + futureTense = map[KubeletOperation]string{ + OperationEdit: "Editing", + OperationDelete: "Deleting", + OperationCreate: "Creating", + } +) + +func PromptUserToAcceptWorkerNodeReboot(operation KubeletOperation, r *rosa.Runtime) bool { + if !confirm.ConfirmRaw(buildPromptMessage(operation, r.GetClusterKey())) { + r.Reporter.Infof(buildAbortMessage(operation, r.GetClusterKey())) + return false + } + return true +} + +func buildAbortMessage(operation KubeletOperation, clusterKey string) string { + return fmt.Sprintf(abortMessage, singularTense[operation], clusterKey) +} + +func buildPromptMessage(operation KubeletOperation, clusterKey string) string { + return fmt.Sprintf(promptMessage, futureTense[operation], clusterKey) +} diff --git a/pkg/kubeletconfig/input_test.go b/pkg/kubeletconfig/input_test.go new file mode 100644 index 0000000000..87d95335d4 --- /dev/null +++ b/pkg/kubeletconfig/input_test.go @@ -0,0 +1,19 @@ +package kubeletconfig + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("KubeletConfig Input", func() { + It("Generates the abort message", func() { + msg := buildAbortMessage(OperationCreate, "foo") + Expect(msg).To(Equal("Create of KubeletConfig for cluster 'foo' aborted.")) + }) + + It("Generates the prompt message", func() { + msg := buildPromptMessage(OperationCreate, "foo") + Expect(msg).To(Equal("Creating the KubeletConfig for cluster 'foo' will cause all non-Control Plane " + + "nodes to reboot. This may cause outages to your applications. Do you wish to continue?")) + }) +}) diff --git a/pkg/kubeletconfig/options.go b/pkg/kubeletconfig/options.go index 13be0ecbdb..0af2c3c68e 100644 --- a/pkg/kubeletconfig/options.go +++ b/pkg/kubeletconfig/options.go @@ -15,14 +15,9 @@ func NewKubeletConfigOptions() *KubeletConfigOptions { return &KubeletConfigOptions{} } -func (k *KubeletConfigOptions) AddFlagsToCommand(cmd *cobra.Command) { +func (k *KubeletConfigOptions) AddNameFlag(cmd *cobra.Command) { flags := cmd.Flags() flags.SortFlags = false - flags.IntVar( - &k.PodPidsLimit, - PodPidsLimitOption, - PodPidsLimitOptionDefaultValue, - PodPidsLimitOptionUsage) flags.StringVar( &k.Name, NameOption, @@ -30,6 +25,17 @@ func (k *KubeletConfigOptions) AddFlagsToCommand(cmd *cobra.Command) { NameOptionUsage) } +func (k *KubeletConfigOptions) AddAllFlags(cmd *cobra.Command) { + flags := cmd.Flags() + flags.SortFlags = false + flags.IntVar( + &k.PodPidsLimit, + PodPidsLimitOption, + PodPidsLimitOptionDefaultValue, + PodPidsLimitOptionUsage) + k.AddNameFlag(cmd) +} + func (k *KubeletConfigOptions) ValidateForHypershift() error { if k.Name == "" { return fmt.Errorf("The --name flag is required for Hosted Control Plane clusters.") diff --git a/pkg/kubeletconfig/options_test.go b/pkg/kubeletconfig/options_test.go index 62a0f827fa..1c5d7bd63f 100644 --- a/pkg/kubeletconfig/options_test.go +++ b/pkg/kubeletconfig/options_test.go @@ -9,7 +9,7 @@ import ( var _ = Describe("KubeletConfigOptions", func() { - It("Adds flags to command", func() { + It("Add all flags to command", func() { cmd := &cobra.Command{} flags := cmd.Flags() Expect(flags).NotTo(BeNil()) @@ -17,7 +17,7 @@ var _ = Describe("KubeletConfigOptions", func() { Expect(flags.Lookup(NameOption)).To(BeNil()) options := NewKubeletConfigOptions() - options.AddFlagsToCommand(cmd) + options.AddAllFlags(cmd) flag := flags.Lookup(PodPidsLimitOption) assertFlag(flag, PodPidsLimitOption, PodPidsLimitOptionUsage) @@ -26,6 +26,22 @@ var _ = Describe("KubeletConfigOptions", func() { assertFlag(flag, NameOption, NameOptionUsage) }) + It("Adds name flag to command", func() { + cmd := &cobra.Command{} + flags := cmd.Flags() + Expect(flags).NotTo(BeNil()) + Expect(flags.Lookup(NameOption)).To(BeNil()) + + options := NewKubeletConfigOptions() + options.AddNameFlag(cmd) + + flag := flags.Lookup(PodPidsLimitOption) + Expect(flag).To(BeNil()) + + flag = flags.Lookup(NameOption) + assertFlag(flag, NameOption, NameOptionUsage) + }) + It("Fails HCP validation if no name supplied", func() { options := NewKubeletConfigOptions() err := options.ValidateForHypershift() diff --git a/pkg/ocm/kubeletconfig.go b/pkg/ocm/kubeletconfig.go index c7adb11301..936e682adb 100644 --- a/pkg/ocm/kubeletconfig.go +++ b/pkg/ocm/kubeletconfig.go @@ -27,8 +27,38 @@ func (c *Client) GetClusterKubeletConfig(clusterID string) (*cmv1.KubeletConfig, return response.Body(), true, nil } -func (c *Client) DeleteKubeletConfig(clusterID string) error { - response, err := c.ocm.ClustersMgmt().V1().Clusters().Cluster(clusterID).KubeletConfig().Delete().Send() +func (c *Client) DeleteKubeletConfigByName(ctx context.Context, clusterId string, name string) error { + kubeletConfig, exists, err := c.FindKubeletConfigByName(ctx, clusterId, name) + if err != nil { + return err + } + + if !exists { + return fmt.Errorf("The KubeletConfig with name '%s' does not exist on cluster '%s'", name, clusterId) + } + + response, err := c.ocm.ClustersMgmt(). + V1(). + Clusters(). + Cluster(clusterId). + KubeletConfigs(). + KubeletConfig(kubeletConfig.ID()). + Delete(). + SendContext(ctx) + + if err != nil { + return handleErr(response.Error(), err) + } + return nil +} + +func (c *Client) DeleteKubeletConfig(ctx context.Context, clusterID string) error { + response, err := c.ocm.ClustersMgmt(). + V1(). + Clusters(). + Cluster(clusterID). + KubeletConfig(). + Delete().SendContext(ctx) if err != nil { return handleErr(response.Error(), err) } diff --git a/pkg/ocm/kubeletconfig_test.go b/pkg/ocm/kubeletconfig_test.go index 53c52ffb3a..5fcdb36825 100644 --- a/pkg/ocm/kubeletconfig_test.go +++ b/pkg/ocm/kubeletconfig_test.go @@ -108,7 +108,7 @@ var _ = Describe("KubeletConfig", Ordered, func() { RespondWithJSON(http.StatusNoContent, ""), ) - err := ocmClient.DeleteKubeletConfig(clusterId) + err := ocmClient.DeleteKubeletConfig(context.Background(), clusterId) Expect(err).To(BeNil()) }) @@ -121,7 +121,7 @@ var _ = Describe("KubeletConfig", Ordered, func() { ), ) - err := ocmClient.DeleteKubeletConfig(clusterId) + err := ocmClient.DeleteKubeletConfig(context.Background(), clusterId) Expect(err).NotTo(BeNil()) }) @@ -264,6 +264,33 @@ var _ = Describe("KubeletConfig", Ordered, func() { }) }) + Context("Delete KubeletConfig by Name", func() { + + It("Deletes the kubeletconfig by name", func() { + apiServer.AppendHandlers( + RespondWithJSON( + http.StatusOK, createKubeletConfigList(false))) + apiServer.RouteToHandler(http.MethodDelete, + fmt.Sprintf("/api/clusters_mgmt/v1/clusters/%s/kubelet_configs/%s", clusterId, kubeletId), + RespondWithJSON(http.StatusNoContent, body)) + + err := ocmClient.DeleteKubeletConfigByName(context.Background(), clusterId, kubeletName) + Expect(err).NotTo(HaveOccurred()) + }) + + It("Fails to delete if the kubeletconfig does not exist", func() { + apiServer.AppendHandlers( + RespondWithJSON( + http.StatusOK, createKubeletConfigList(false))) + + err := ocmClient.DeleteKubeletConfigByName(context.Background(), clusterId, "notExisting") + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To( + ContainSubstring( + fmt.Sprintf( + "The KubeletConfig with name 'notExisting' does not exist on cluster '%s'", clusterId))) + }) + }) }) func createKubeletConfig() (string, error) {