Reputation: 1580
In bash scripts, I normally use 'kubectl wait' to block until a certain pod resource is ready, e.g. something similar to this:
kubectl wait --for=condition=Ready --timeout=2m -n mynamespace pod -l myselector
This works well because often times I don't know the exact name of the pod I need to wait for, and 'kubectl wait' allows me to locate the pod based on selectors and then block until it's ready.
Now I need to do something similar in golang code. I have seen examples of using the client-go library to authenticate and 'get' a specific pod by name. But I have a few questions on how to best adapt this example to my needs...
I do not know the exact/full name of the pod to be able to 'Get()' it, which is why 'kubectl wait' is perfect as it allows me to find the pod using selectors. I assume that I should use client-go library to instead do a CoreV1().Pods().List() call instead of a Get() in order to allow me to find the pod I want using selectors?
Also, the pod may not exist immediately and might be created only after 1 minute or so, which 'kubectl wait' handles for me. In code, do I need to loop/sleep and keep performing List() until the pod exists?
Similar question to #2...once the List() does return a pod name, what is the best way in golang to 'wait' for that pod to be in a 'ready' state? I do not want to do any ugly polls with sleeps if avoidable...so is there is a better option using golang 'wait' package or similar? What do you recommend?
Upvotes: 7
Views: 6444
Reputation: 61521
How about doing it exactly the way kubectl
does it? Basically, using List(...) to list based on a field selector and then Watch(...)
Snippet:
...
// List with a name field selector to get the current resourceVersion to watch from (not the object's resourceVersion)
gottenObjList, err := o.DynamicClient.Resource(info.Mapping.Resource).Namespace(info.Namespace).List(context.TODO(), metav1.ListOptions{FieldSelector: nameSelector})
if apierrors.IsNotFound(err) {
return info.Object, true, nil
}
if err != nil {
// TODO this could do something slightly fancier if we wish
return info.Object, false, err
}
if len(gottenObjList.Items) != 1 {
return info.Object, true, nil
}
gottenObj := &gottenObjList.Items[0]
resourceLocation := ResourceLocation{
GroupResource: info.Mapping.Resource.GroupResource(),
Namespace: gottenObj.GetNamespace(),
Name: gottenObj.GetName(),
}
if uid, ok := o.UIDMap[resourceLocation]; ok {
if gottenObj.GetUID() != uid {
return gottenObj, true, nil
}
}
watchOptions := metav1.ListOptions{}
watchOptions.FieldSelector = nameSelector
watchOptions.ResourceVersion = gottenObjList.GetResourceVersion()
objWatch, err := o.DynamicClient.Resource(info.Mapping.Resource).Namespace(info.Namespace).Watch(context.TODO(), watchOptions)
if err != nil {
return gottenObj, false, err
}
...
✌️
Upvotes: 6