github.com/SupersunnySea/draft@v0.16.0/pkg/kube/podutil/podutil.go (about) 1 // package podutil exists for functions that exist in k8s.io/kubernetes but not in k8s.io/client-go. Most of the things here should be contributed upstream. 2 3 package podutil 4 5 import ( 6 "fmt" 7 "time" 8 9 "k8s.io/api/core/v1" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 "k8s.io/apimachinery/pkg/fields" 12 klabels "k8s.io/apimachinery/pkg/labels" 13 "k8s.io/client-go/kubernetes" 14 "k8s.io/client-go/tools/cache" 15 ) 16 17 // IsPodReady returns true if a pod is ready; false otherwise. 18 func IsPodReady(pod *v1.Pod) bool { 19 return IsPodReadyConditionTrue(pod.Status) 20 } 21 22 // IsPodReadyConditionTrue returns true if a pod is ready; false otherwise. 23 func IsPodReadyConditionTrue(status v1.PodStatus) bool { 24 condition := GetPodReadyCondition(status) 25 return condition != nil && condition.Status == v1.ConditionTrue 26 } 27 28 // GetPodReadyCondition extracts the pod ready condition from the given status and returns that. 29 // Returns nil if the condition is not present. 30 func GetPodReadyCondition(status v1.PodStatus) *v1.PodCondition { 31 _, condition := GetPodCondition(&status, v1.PodReady) 32 return condition 33 } 34 35 // GetPodCondition extracts the provided condition from the given status and returns that. 36 // Returns nil and -1 if the condition is not present, and the index of the located condition. 37 func GetPodCondition(status *v1.PodStatus, conditionType v1.PodConditionType) (int, *v1.PodCondition) { 38 if status == nil { 39 return -1, nil 40 } 41 for i := range status.Conditions { 42 if status.Conditions[i].Type == conditionType { 43 return i, &status.Conditions[i] 44 } 45 } 46 return -1, nil 47 } 48 49 // GetPod waits for a pod with the specified label to be ready, then returns it 50 // if no pod is ready, it checks every second until a pod is ready until timeout is reached 51 func GetPod(namespace string, draftLabelKey, name, annotationKey, buildID string, clientset kubernetes.Interface) (*v1.Pod, error) { 52 var targetPod *v1.Pod 53 s := newStopChan() 54 55 listwatch := cache.NewListWatchFromClient(clientset.CoreV1().RESTClient(), "pods", namespace, fields.Everything()) 56 _, controller := cache.NewInformer(listwatch, &v1.Pod{}, time.Second, cache.ResourceEventHandlerFuncs{ 57 UpdateFunc: func(o, n interface{}) { 58 newPod := n.(*v1.Pod) 59 60 // check the pod label and if pod is in terminating state 61 if (newPod.Labels[draftLabelKey] != name) || (newPod.Annotations[annotationKey] != buildID) || (newPod.ObjectMeta.DeletionTimestamp != nil) { 62 return 63 } 64 65 if IsPodReady(newPod) { 66 targetPod = newPod 67 s.closeOnce() 68 } 69 }, 70 }) 71 72 go func() { 73 controller.Run(s.c) 74 }() 75 76 select { 77 case <-s.c: 78 return targetPod, nil 79 case <-time.After(5 * time.Minute): 80 return nil, fmt.Errorf("cannot get pod with buildID %v: timed out", buildID) 81 } 82 } 83 84 // ListPods returns pods in the given namespace that match the labels and 85 // annotations given 86 func ListPods(namespace string, labels, annotations map[string]string, clientset kubernetes.Interface) ([]v1.Pod, error) { 87 pods := []v1.Pod{} 88 89 labelSet := klabels.Set{} 90 for k, v := range labels { 91 labelSet[k] = v 92 } 93 94 podList, err := clientset.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSet.AsSelector().String()}) 95 if err != nil { 96 return nil, err 97 } 98 99 // return pod names that match annotations 100 for _, pod := range podList.Items { 101 annosFound := make([]bool, len(annotations)) 102 count := 0 103 for k, v := range annotations { 104 if pod.Annotations[k] == v { 105 annosFound[count] = true 106 } else { 107 annosFound[count] = false 108 } 109 count = count + 1 110 } 111 if allAnnotationsFound(annosFound) { 112 pods = append(pods, pod) 113 } 114 } 115 116 return pods, nil 117 } 118 119 // ListPodNames returns pod names from given namespace that match labels and 120 // annotations given 121 func ListPodNames(namespace string, labels, annotations map[string]string, clientset kubernetes.Interface) ([]string, error) { 122 names := []string{} 123 124 pods, err := ListPods(namespace, labels, annotations, clientset) 125 if err != nil { 126 return nil, err 127 } 128 129 for _, pod := range pods { 130 names = append(names, pod.Name) 131 } 132 133 return names, nil 134 } 135 136 func allAnnotationsFound(results []bool) bool { 137 for _, k := range results { 138 if k == false { 139 return false 140 } 141 } 142 return true 143 }