From 97fe285adad8e343c7d2d7c44fcd07d9d633970c Mon Sep 17 00:00:00 2001 From: Jacob LeGrone Date: Sat, 20 Jul 2019 13:14:01 -0400 Subject: [PATCH] feat(client): wait for Pods during hook execution Signed-off-by: Jacob LeGrone --- pkg/kube/client.go | 31 ++++++++++++++++++++++++++++++- pkg/kube/interface.go | 5 +++-- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 4aa817af3..2162f083f 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -255,6 +255,8 @@ func (c *Client) watchTimeout(t time.Duration) func(*resource.Info) error { // // - Jobs: A job is marked "Ready" when it has successfully completed. This is // ascertained by watching the Status fields in a job's output. +// - Pods: A pod is marked "Ready" when it has successfully completed. This is +// ascertained by watching the status.phase field in a pod's output. // // Handling for other kinds will be added as necessary. func (c *Client) WatchUntilReady(reader io.Reader, timeout time.Duration) error { @@ -435,8 +437,11 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err // the status go into a good state. For other types, like ReplicaSet // we don't really do anything to support these as hooks. c.Log("Add/Modify event for %s: %v", info.Name, e.Type) - if kind == "Job" { + switch kind { + case "Job": return c.waitForJob(e, info.Name) + case "Pod": + return c.waitForPodSuccess(e, info.Name) } return true, nil case watch.Deleted: @@ -474,6 +479,30 @@ func (c *Client) waitForJob(e watch.Event, name string) (bool, error) { return false, nil } +// waitForPodSuccess is a helper that waits for a pod to complete. +// +// This operates on an event returned from a watcher. +func (c *Client) waitForPodSuccess(e watch.Event, name string) (bool, error) { + o, ok := e.Object.(*v1.Pod) + if !ok { + return true, errors.Errorf("expected %s to be a *v1.Pod, got %T", name, e.Object) + } + + switch o.Status.Phase { + case v1.PodSucceeded: + fmt.Printf("Pod %s succeeded\n", o.Name) + return true, nil + case v1.PodFailed: + return true, errors.Errorf("pod %s failed", o.Name) + case v1.PodPending: + fmt.Printf("Pod %s pending\n", o.Name) + case v1.PodRunning: + fmt.Printf("Pod %s running\n", o.Name) + } + + return false, nil +} + // scrubValidationError removes kubectl info from the message. func scrubValidationError(err error) error { if err == nil { diff --git a/pkg/kube/interface.go b/pkg/kube/interface.go index 72d7a0ea9..53da50b8b 100644 --- a/pkg/kube/interface.go +++ b/pkg/kube/interface.go @@ -21,7 +21,7 @@ import ( "time" ) -// KubernetesClient represents a client capable of communicating with the Kubernetes API. +// Interface represents a client capable of communicating with the Kubernetes API. // // A KubernetesClient must be concurrency safe. type Interface interface { @@ -41,7 +41,8 @@ type Interface interface { // Watch the resource in reader until it is "ready". // - // For Jobs, "ready" means the job ran to completion (excited without error). + // For Jobs, "ready" means the Job ran to completion (exited without error). + // For Pods, "ready" means the Pod phase is marked "succeeded". // For all other kinds, it means the kind was created or modified without // error. WatchUntilReady(reader io.Reader, timeout time.Duration) error