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  }