github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/controllers/apps/operations/stop.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package operations 21 22 import ( 23 "encoding/json" 24 "time" 25 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "sigs.k8s.io/controller-runtime/pkg/client" 28 29 appsv1alpha1 "github.com/1aal/kubeblocks/apis/apps/v1alpha1" 30 "github.com/1aal/kubeblocks/pkg/constant" 31 intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil" 32 ) 33 34 type StopOpsHandler struct{} 35 36 var _ OpsHandler = StopOpsHandler{} 37 38 func init() { 39 stopBehaviour := OpsBehaviour{ 40 FromClusterPhases: appsv1alpha1.GetClusterUpRunningPhases(), 41 ToClusterPhase: appsv1alpha1.StoppingClusterPhase, 42 OpsHandler: StopOpsHandler{}, 43 ProcessingReasonInClusterCondition: ProcessingReasonStopping, 44 } 45 46 opsMgr := GetOpsManager() 47 opsMgr.RegisterOps(appsv1alpha1.StopType, stopBehaviour) 48 } 49 50 // ActionStartedCondition the started condition when handling the stop request. 51 func (stop StopOpsHandler) ActionStartedCondition(reqCtx intctrlutil.RequestCtx, cli client.Client, opsRes *OpsResource) (*metav1.Condition, error) { 52 return appsv1alpha1.NewStopCondition(opsRes.OpsRequest), nil 53 } 54 55 // Action modifies Cluster.spec.components[*].replicas from the opsRequest 56 func (stop StopOpsHandler) Action(reqCtx intctrlutil.RequestCtx, cli client.Client, opsRes *OpsResource) error { 57 var ( 58 expectReplicas = int32(0) 59 componentReplicasMap = map[string]int32{} 60 cluster = opsRes.Cluster 61 ) 62 if _, ok := cluster.Annotations[constant.SnapShotForStartAnnotationKey]; ok { 63 return nil 64 } 65 for i, v := range cluster.Spec.ComponentSpecs { 66 componentReplicasMap[v.Name] = v.Replicas 67 cluster.Spec.ComponentSpecs[i].Replicas = expectReplicas 68 } 69 componentReplicasSnapshot, err := json.Marshal(componentReplicasMap) 70 if err != nil { 71 return err 72 } 73 if cluster.Annotations == nil { 74 cluster.Annotations = map[string]string{} 75 } 76 // record the replicas snapshot of components to the annotations of cluster before stopping the cluster. 77 cluster.Annotations[constant.SnapShotForStartAnnotationKey] = string(componentReplicasSnapshot) 78 return cli.Update(reqCtx.Ctx, cluster) 79 } 80 81 // ReconcileAction will be performed when action is done and loops till OpsRequest.status.phase is Succeed/Failed. 82 // the Reconcile function for stop opsRequest. 83 func (stop StopOpsHandler) ReconcileAction(reqCtx intctrlutil.RequestCtx, cli client.Client, opsRes *OpsResource) (appsv1alpha1.OpsPhase, time.Duration, error) { 84 getExpectReplicas := func(opsRequest *appsv1alpha1.OpsRequest, componentName string) *int32 { 85 expectReplicas := int32(0) 86 return &expectReplicas 87 } 88 handleComponentProgress := func(reqCtx intctrlutil.RequestCtx, 89 cli client.Client, 90 opsRes *OpsResource, 91 pgRes progressResource, 92 compStatus *appsv1alpha1.OpsRequestComponentStatus) (int32, int32, error) { 93 expectProgressCount, completedCount, err := handleComponentProgressForScalingReplicas(reqCtx, cli, opsRes, pgRes, compStatus, getExpectReplicas) 94 if err != nil { 95 return expectProgressCount, completedCount, err 96 } 97 return expectProgressCount, completedCount, nil 98 } 99 return reconcileActionWithComponentOps(reqCtx, cli, opsRes, "", handleComponentProgress) 100 } 101 102 // SaveLastConfiguration records last configuration to the OpsRequest.status.lastConfiguration 103 func (stop StopOpsHandler) SaveLastConfiguration(reqCtx intctrlutil.RequestCtx, cli client.Client, opsRes *OpsResource) error { 104 opsRequest := opsRes.OpsRequest 105 lastComponentInfo := map[string]appsv1alpha1.LastComponentConfiguration{} 106 for _, v := range opsRes.Cluster.Spec.ComponentSpecs { 107 if v.Replicas != 0 { 108 podNames, err := getCompPodNamesBeforeScaleDownReplicas(reqCtx, cli, *opsRes.Cluster, v.Name) 109 if err != nil { 110 return err 111 } 112 copyReplicas := v.Replicas 113 lastComponentInfo[v.Name] = appsv1alpha1.LastComponentConfiguration{ 114 Replicas: ©Replicas, 115 TargetResources: map[appsv1alpha1.ComponentResourceKey][]string{ 116 appsv1alpha1.PodsCompResourceKey: podNames, 117 }, 118 } 119 } 120 } 121 opsRequest.Status.LastConfiguration.Components = lastComponentInfo 122 return nil 123 }