github.com/verrazzano/verrazzano@v1.7.0/pkg/k8s/ready/statefulset_ready.go (about) 1 // Copyright (c) 2021, 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package ready 5 6 import ( 7 "context" 8 9 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 10 11 appsv1 "k8s.io/api/apps/v1" 12 corev1 "k8s.io/api/core/v1" 13 "k8s.io/apimachinery/pkg/api/errors" 14 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 "k8s.io/apimachinery/pkg/types" 16 "sigs.k8s.io/controller-runtime/pkg/client" 17 ) 18 19 // pod label used to identify the controllerRevision resource for daemonsets and statefulsets 20 const controllerRevisionHashLabel = "controller-revision-hash" 21 22 // StatefulSetsAreReady Check that the named statefulsets have the minimum number of specified replicas ready and available 23 func StatefulSetsAreReady(log vzlog.VerrazzanoLogger, client client.Client, namespacedNames []types.NamespacedName, expectedReplicas int32, prefix string) bool { 24 for _, namespacedName := range namespacedNames { 25 statefulset := appsv1.StatefulSet{} 26 if err := client.Get(context.TODO(), namespacedName, &statefulset); err != nil { 27 if errors.IsNotFound(err) { 28 log.Progressf("%s is waiting for statefulset %v to exist", prefix, namespacedName) 29 // StatefulSet not found 30 return false 31 } 32 log.Errorf("Failed getting statefulset %v: %v", namespacedName, err) 33 return false 34 } 35 if statefulset.Status.UpdatedReplicas < expectedReplicas { 36 log.Progressf("%s is waiting for statefulset %s replicas to be %v. Current updated replicas is %v", prefix, namespacedName, 37 expectedReplicas, statefulset.Status.UpdatedReplicas) 38 return false 39 } 40 if statefulset.Status.ReadyReplicas < expectedReplicas { 41 log.Progressf("%s is waiting for statefulset %s replicas to be %v. Current ready replicas is %v", prefix, namespacedName, 42 expectedReplicas, statefulset.Status.ReadyReplicas) 43 return false 44 } 45 if !PodsReadyStatefulSet(log, client, namespacedName, statefulset.Spec.Selector, expectedReplicas, prefix) { 46 return false 47 } 48 log.Oncef("%s has enough replicas for statefulsets %v", prefix, namespacedName) 49 } 50 return true 51 } 52 53 // DoStatefulSetsExist checks if all the named statefulsets exist 54 func DoStatefulSetsExist(log vzlog.VerrazzanoLogger, client client.Client, namespacedNames []types.NamespacedName, _ int32, prefix string) bool { 55 for _, namespacedName := range namespacedNames { 56 exists, err := DoesStatefulsetExist(client, namespacedName) 57 if err != nil { 58 logErrorf(log, "%s failed getting statefulset %v: %v", prefix, namespacedName, err) 59 return false 60 } 61 if !exists { 62 logProgressf(log, "%s is waiting for statefulset %v to exist", prefix, namespacedName) 63 return false 64 } 65 } 66 return true 67 } 68 69 // DoesStatefulsetExist checks if the named statefulset exists 70 func DoesStatefulsetExist(client client.Client, namespacedName types.NamespacedName) (bool, error) { 71 sts := appsv1.StatefulSet{} 72 if err := client.Get(context.TODO(), namespacedName, &sts); err != nil { 73 if errors.IsNotFound(err) { 74 return false, nil 75 } 76 return false, err 77 } 78 return true, nil 79 } 80 81 // PodsReadyStatefulSet checks for an expected number of pods to be using the latest controllerRevision resource and are 82 // running and ready 83 func PodsReadyStatefulSet(log vzlog.VerrazzanoLogger, client client.Client, namespacedName types.NamespacedName, selector *metav1.LabelSelector, expectedReplicas int32, prefix string) bool { 84 // Get a list of pods for a given namespace and labels selector 85 pods := GetPodsList(log, client, namespacedName, selector) 86 if pods == nil { 87 return false 88 } 89 90 // If no pods found log a progress message and return 91 if len(pods.Items) == 0 { 92 log.Progressf("Found no pods with matching labels selector %v for namespace %s", selector, namespacedName.Namespace) 93 return false 94 } 95 96 // Loop through pods identifying pods that are using the latest controllerRevision resource 97 var savedPods []corev1.Pod 98 var savedRevision int64 99 var savedControllerRevisionHash string 100 for _, pod := range pods.Items { 101 // Log error and return if the controller-revision-hash label is not found. This should never happen. 102 if _, ok := pod.Labels[controllerRevisionHashLabel]; !ok { 103 log.Errorf("Failed to find pod label [controller-revision-hash] for pod %s/%s", pod.Namespace, pod.Name) 104 return false 105 } 106 107 if pod.Labels[controllerRevisionHashLabel] == savedControllerRevisionHash { 108 savedPods = append(savedPods, pod) 109 continue 110 } 111 112 // Get the controllerRevision resource for the pod given the controller-revision-hash label 113 var cr appsv1.ControllerRevision 114 err := client.Get(context.TODO(), types.NamespacedName{Namespace: namespacedName.Namespace, Name: pod.Labels[controllerRevisionHashLabel]}, &cr) 115 if err != nil { 116 log.Errorf("Failed to get controllerRevision %s: %v", namespacedName, err) 117 return false 118 } 119 120 if cr.Revision > savedRevision { 121 savedRevision = cr.Revision 122 savedControllerRevisionHash = pod.Labels[controllerRevisionHashLabel] 123 savedPods = []corev1.Pod{} 124 savedPods = append(savedPods, pod) 125 } 126 } 127 // Make sure pods using the latest controllerRevision resource are ready. 128 podsReady, success := EnsurePodsAreReady(log, savedPods, expectedReplicas, prefix) 129 if !success { 130 return false 131 } 132 133 if podsReady < expectedReplicas { 134 log.Progressf("%s is waiting for statefulset %s pods to be %v. Current available pods are %v", prefix, namespacedName, 135 expectedReplicas, podsReady) 136 return false 137 } 138 139 return true 140 }