From 9bec95d16cb577190fbfa1fe1e92dd407e2a3594 Mon Sep 17 00:00:00 2001 From: avanish23 Date: Wed, 30 Oct 2024 23:08:22 +0530 Subject: [PATCH 1/3] make daemon set restartable --- modules/api/pkg/handler/apihandler.go | 26 +++++++++++ modules/api/pkg/resource/daemonset/restart.go | 46 +++++++++++++++++++ modules/common/types/resourcekind.go | 1 + 3 files changed, 73 insertions(+) create mode 100644 modules/api/pkg/resource/daemonset/restart.go diff --git a/modules/api/pkg/handler/apihandler.go b/modules/api/pkg/handler/apihandler.go index f863babaffd7..eb0001134038 100644 --- a/modules/api/pkg/handler/apihandler.go +++ b/modules/api/pkg/handler/apihandler.go @@ -454,6 +454,15 @@ func CreateHTTPAPIHandler(iManager integration.Manager) (*restful.Container, err Param(apiV1Ws.PathParameter("daemonSet", "name of the DaemonSet")). Writes(common.EventList{}). Returns(http.StatusOK, "OK", common.EventList{})) + apiV1Ws.Route( + apiV1Ws.PUT("/daemonset/{namespace}/{daemonSet}/restart").To(apiHandler.handleDaemonSetRestart). + // docs + Doc("rollout restart of the Daemon Set"). + Param(apiV1Ws.PathParameter("namespace", "namespace of the Daemon Set")). + Param(apiV1Ws.PathParameter("daemonSet", "name of the Daemon Set")). + Writes(deployment.RolloutSpec{}). + Returns(http.StatusOK, "OK", daemonset.DaemonSetDetail{}), + ) // HorizontalPodAutoscaler apiV1Ws.Route( @@ -2801,6 +2810,23 @@ func (apiHandler *APIHandler) handleGetDaemonSetEvents(request *restful.Request, _ = response.WriteHeaderAndEntity(http.StatusOK, result) } +func (apiHandle *APIHandler) handleDaemonSetRestart(request *restful.Request, response *restful.Response) { + k8sClient, err := client.Client(request.Request) + if err != nil { + errors.HandleInternalError(response, err) + return + } + + namespace := request.PathParameter("namespace") + name := request.PathParameter("daemonSet") + result, err := daemonset.RestartDaemonSet(k8sClient, namespace, name) + if err != nil { + errors.HandleInternalError(response, err) + return + } + _ = response.WriteHeaderAndEntity(http.StatusOK, result) +} + func (apiHandler *APIHandler) handleGetHorizontalPodAutoscalerList(request *restful.Request, response *restful.Response) { k8sClient, err := client.Client(request.Request) diff --git a/modules/api/pkg/resource/daemonset/restart.go b/modules/api/pkg/resource/daemonset/restart.go new file mode 100644 index 000000000000..f988816937fd --- /dev/null +++ b/modules/api/pkg/resource/daemonset/restart.go @@ -0,0 +1,46 @@ +// Copyright 2017 The Kubernetes Authors. +// +// 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 +// +// http://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 daemonset + +import ( + "context" + v1 "k8s.io/api/apps/v1" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + client "k8s.io/client-go/kubernetes" + "time" +) + +const ( + // RestartedAtAnnotationKey is an annotation key for rollout restart + RestartedAtAnnotationKey = "kubectl.kubernetes.io/restartedAt" +) + +// RestartDaemonSet restarts a daemon set in the manner of `kubectl rollout restart`. +func RestartDaemonSet(client client.Interface, namespace, name string) (*v1.DaemonSet, error) { + daemonSet, err := client.AppsV1().DaemonSets(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) + if err != nil { + return nil, err + } + + if daemonSet.Spec.Template.ObjectMeta.Annotations == nil { + daemonSet.Spec.Template.ObjectMeta.Annotations = map[string]string{} + } + daemonSet.Spec.Template.ObjectMeta.Annotations[RestartedAtAnnotationKey] = time.Now().Format(time.RFC3339) + _, err = client.AppsV1().DaemonSets(namespace).Update(context.TODO(), daemonSet, metaV1.UpdateOptions{}) + if err != nil { + return nil, err + } + return daemonSet, nil +} diff --git a/modules/common/types/resourcekind.go b/modules/common/types/resourcekind.go index 68946c62818d..c3b2cb0f02e6 100644 --- a/modules/common/types/resourcekind.go +++ b/modules/common/types/resourcekind.go @@ -75,6 +75,7 @@ func (k ResourceKind) Scalable() bool { func (k ResourceKind) Restartable() bool { restartable := []ResourceKind{ ResourceKindDeployment, + ResourceKindDaemonSet, } for _, kind := range restartable { From e964d6e6e570a6e6962f6f7d79d233f6fd2bccf4 Mon Sep 17 00:00:00 2001 From: avanish23 Date: Mon, 20 Jan 2025 09:21:35 +0530 Subject: [PATCH 2/3] make stateful set restartable --- modules/api/pkg/handler/apihandler.go | 26 +++++++++++++++ .../api/pkg/resource/statefulset/restart.go | 32 +++++++++++++++++++ modules/common/types/resourcekind.go | 1 + 3 files changed, 59 insertions(+) create mode 100644 modules/api/pkg/resource/statefulset/restart.go diff --git a/modules/api/pkg/handler/apihandler.go b/modules/api/pkg/handler/apihandler.go index eb0001134038..e383fa73edf8 100644 --- a/modules/api/pkg/handler/apihandler.go +++ b/modules/api/pkg/handler/apihandler.go @@ -855,6 +855,15 @@ func CreateHTTPAPIHandler(iManager integration.Manager) (*restful.Container, err Param(apiV1Ws.PathParameter("statefulset", "name of the StatefulSet")). Writes(common.EventList{}). Returns(http.StatusOK, "OK", common.EventList{})) + apiV1Ws.Route( + apiV1Ws.PUT("/statefulset/{namespace}/{statefulset}/restart").To(apiHandler.handleStatefulSetRestart). + // docs + Doc("rollout restart of the Daemon Set"). + Param(apiV1Ws.PathParameter("namespace", "namespace of the StatefulSet")). + Param(apiV1Ws.PathParameter("statefulset", "name of the StatefulSet")). + Writes(deployment.RolloutSpec{}). + Returns(http.StatusOK, "OK", statefulset.StatefulSetDetail{}), + ) // Node apiV1Ws.Route( @@ -2827,6 +2836,23 @@ func (apiHandle *APIHandler) handleDaemonSetRestart(request *restful.Request, re _ = response.WriteHeaderAndEntity(http.StatusOK, result) } +func (apiHandle *APIHandler) handleStatefulSetRestart(request *restful.Request, response *restful.Response) { + k8sClient, err := client.Client(request.Request) + if err != nil { + errors.HandleInternalError(response, err) + return + } + + namespace := request.PathParameter("namespace") + name := request.PathParameter("daemonSet") + result, err := statefulset.RestartStatefulSet(k8sClient, namespace, name) + if err != nil { + errors.HandleInternalError(response, err) + return + } + _ = response.WriteHeaderAndEntity(http.StatusOK, result) +} + func (apiHandler *APIHandler) handleGetHorizontalPodAutoscalerList(request *restful.Request, response *restful.Response) { k8sClient, err := client.Client(request.Request) diff --git a/modules/api/pkg/resource/statefulset/restart.go b/modules/api/pkg/resource/statefulset/restart.go new file mode 100644 index 000000000000..3b8b1802cf9b --- /dev/null +++ b/modules/api/pkg/resource/statefulset/restart.go @@ -0,0 +1,32 @@ +package statefulset + +import ( + "context" + v1 "k8s.io/api/apps/v1" + metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" + client "k8s.io/client-go/kubernetes" + "time" +) + +const ( + // RestartedAtAnnotationKey is an annotation key for rollout restart + RestartedAtAnnotationKey = "kubectl.kubernetes.io/restartedAt" +) + +// RestartStatefulSet restarts a daemon set in the manner of `kubectl rollout restart`. +func RestartStatefulSet(client client.Interface, namespace, name string) (*v1.StatefulSet, error) { + statefulSet, err := client.AppsV1().StatefulSets(namespace).Get(context.TODO(), name, metaV1.GetOptions{}) + if err != nil { + return nil, err + } + + if statefulSet.Spec.Template.ObjectMeta.Annotations == nil { + statefulSet.Spec.Template.ObjectMeta.Annotations = map[string]string{} + } + statefulSet.Spec.Template.ObjectMeta.Annotations[RestartedAtAnnotationKey] = time.Now().Format(time.RFC3339) + _, err = client.AppsV1().StatefulSets(namespace).Update(context.TODO(), statefulSet, metaV1.UpdateOptions{}) + if err != nil { + return nil, err + } + return statefulSet, nil +} diff --git a/modules/common/types/resourcekind.go b/modules/common/types/resourcekind.go index c3b2cb0f02e6..39ca1e1ef802 100644 --- a/modules/common/types/resourcekind.go +++ b/modules/common/types/resourcekind.go @@ -76,6 +76,7 @@ func (k ResourceKind) Restartable() bool { restartable := []ResourceKind{ ResourceKindDeployment, ResourceKindDaemonSet, + ResourceKindStatefulSet, } for _, kind := range restartable { From 5050bd65194054bcdbfdd562f92848c28d5052e0 Mon Sep 17 00:00:00 2001 From: avanish23 Date: Fri, 24 Jan 2025 19:45:29 +0530 Subject: [PATCH 3/3] addressed PR comments --- modules/api/pkg/resource/daemonset/restart.go | 6 +----- modules/api/pkg/resource/statefulset/restart.go | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/modules/api/pkg/resource/daemonset/restart.go b/modules/api/pkg/resource/daemonset/restart.go index f988816937fd..3357f2ac2dd8 100644 --- a/modules/api/pkg/resource/daemonset/restart.go +++ b/modules/api/pkg/resource/daemonset/restart.go @@ -38,9 +38,5 @@ func RestartDaemonSet(client client.Interface, namespace, name string) (*v1.Daem daemonSet.Spec.Template.ObjectMeta.Annotations = map[string]string{} } daemonSet.Spec.Template.ObjectMeta.Annotations[RestartedAtAnnotationKey] = time.Now().Format(time.RFC3339) - _, err = client.AppsV1().DaemonSets(namespace).Update(context.TODO(), daemonSet, metaV1.UpdateOptions{}) - if err != nil { - return nil, err - } - return daemonSet, nil + return client.AppsV1().DaemonSets(namespace).Update(context.TODO(), daemonSet, metaV1.UpdateOptions{}) } diff --git a/modules/api/pkg/resource/statefulset/restart.go b/modules/api/pkg/resource/statefulset/restart.go index 3b8b1802cf9b..48bd47ecb28a 100644 --- a/modules/api/pkg/resource/statefulset/restart.go +++ b/modules/api/pkg/resource/statefulset/restart.go @@ -24,9 +24,5 @@ func RestartStatefulSet(client client.Interface, namespace, name string) (*v1.St statefulSet.Spec.Template.ObjectMeta.Annotations = map[string]string{} } statefulSet.Spec.Template.ObjectMeta.Annotations[RestartedAtAnnotationKey] = time.Now().Format(time.RFC3339) - _, err = client.AppsV1().StatefulSets(namespace).Update(context.TODO(), statefulSet, metaV1.UpdateOptions{}) - if err != nil { - return nil, err - } - return statefulSet, nil + return client.AppsV1().StatefulSets(namespace).Update(context.TODO(), statefulSet, metaV1.UpdateOptions{}) }