github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/common/stateful_set_utils.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 common 21 22 import ( 23 "context" 24 "regexp" 25 "strconv" 26 27 appsv1 "k8s.io/api/apps/v1" 28 corev1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "sigs.k8s.io/controller-runtime/pkg/client" 31 32 intctrlutil "github.com/1aal/kubeblocks/pkg/controllerutil" 33 ) 34 35 // DescendingOrdinalSts is a sort.Interface that Sorts a list of StatefulSet based on the ordinals extracted from the statefulSet. 36 type DescendingOrdinalSts []*appsv1.StatefulSet 37 38 // statefulSetRegex is a regular expression that extracts StatefulSet's ordinal from the Name of StatefulSet 39 var statefulSetRegex = regexp.MustCompile("(.*)-([0-9]+)$") 40 41 // getParentName gets the name of pod's parent StatefulSet. If pod has not parent, the empty string is returned. 42 func getParentName(pod *corev1.Pod) string { 43 parent, _ := intctrlutil.GetParentNameAndOrdinal(pod) 44 return parent 45 } 46 47 // IsMemberOf tests if pod is a member of set. 48 func IsMemberOf(set *appsv1.StatefulSet, pod *corev1.Pod) bool { 49 return getParentName(pod) == set.Name 50 } 51 52 // statefulSetOfComponentIsReady checks if statefulSet of component is ready. 53 func statefulSetOfComponentIsReady(sts *appsv1.StatefulSet, statefulStatusRevisionIsEquals bool, targetReplicas *int32) bool { 54 if targetReplicas == nil { 55 targetReplicas = sts.Spec.Replicas 56 } 57 return statefulSetPodsAreReady(sts, *targetReplicas) && statefulStatusRevisionIsEquals 58 } 59 60 // statefulSetPodsAreReady checks if all pods of statefulSet are ready. 61 func statefulSetPodsAreReady(sts *appsv1.StatefulSet, targetReplicas int32) bool { 62 return sts.Status.AvailableReplicas == targetReplicas && 63 sts.Status.Replicas == targetReplicas && 64 sts.Status.ObservedGeneration == sts.Generation 65 } 66 67 func convertToStatefulSet(obj client.Object) *appsv1.StatefulSet { 68 if obj == nil { 69 return nil 70 } 71 if sts, ok := obj.(*appsv1.StatefulSet); ok { 72 return sts 73 } 74 return nil 75 } 76 77 // ParseParentNameAndOrdinal gets the name of cluster-component and StatefulSet's ordinal as extracted from its Name. If 78 // the StatefulSet's Name was not match a statefulSetRegex, its parent is considered to be empty string, 79 // and its ordinal is considered to be -1. 80 func ParseParentNameAndOrdinal(s string) (string, int32) { 81 parent := "" 82 ordinal := int32(-1) 83 subMatches := statefulSetRegex.FindStringSubmatch(s) 84 if len(subMatches) < 3 { 85 return parent, ordinal 86 } 87 parent = subMatches[1] 88 if i, err := strconv.ParseInt(subMatches[2], 10, 32); err == nil { 89 ordinal = int32(i) 90 } 91 return parent, ordinal 92 } 93 94 // GetPodListByStatefulSet gets statefulSet pod list. 95 func GetPodListByStatefulSet(ctx context.Context, cli client.Client, stsObj *appsv1.StatefulSet) ([]corev1.Pod, error) { 96 selector, err := metav1.LabelSelectorAsMap(stsObj.Spec.Selector) 97 if err != nil { 98 return nil, err 99 } 100 return GetPodListByStatefulSetWithSelector(ctx, cli, stsObj, selector) 101 } 102 103 // GetPodListByStatefulSetWithSelector gets statefulSet pod list. 104 func GetPodListByStatefulSetWithSelector(ctx context.Context, cli client.Client, stsObj *appsv1.StatefulSet, selector client.MatchingLabels) ([]corev1.Pod, error) { 105 podList := &corev1.PodList{} 106 if err := cli.List(ctx, podList, 107 &client.ListOptions{Namespace: stsObj.Namespace}, 108 selector); err != nil { 109 return nil, err 110 } 111 var pods []corev1.Pod 112 for _, pod := range podList.Items { 113 if IsMemberOf(stsObj, &pod) { 114 pods = append(pods, pod) 115 } 116 } 117 return pods, nil 118 }