From 1b3ecc1a3d9a6a10d87fbd4d9a9c316fd3c6a8bf Mon Sep 17 00:00:00 2001 From: Suleiman Dibirov Date: Mon, 17 Jun 2024 12:48:44 +0300 Subject: [PATCH] feat: add pod fail details Signed-off-by: Suleiman Dibirov --- pkg/kube/ready.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ pkg/kube/wait.go | 1 + 2 files changed, 45 insertions(+) diff --git a/pkg/kube/ready.go b/pkg/kube/ready.go index b2d26ba76..9f9c097ff 100644 --- a/pkg/kube/ready.go +++ b/pkg/kube/ready.go @@ -38,6 +38,13 @@ import ( deploymentutil "helm.sh/helm/v3/internal/third_party/k8s.io/kubernetes/deployment/util" ) +type PodError struct { + PodName string + Container string + Reason string + Message string +} + // ReadyCheckerOption is a function that configures a ReadyChecker. type ReadyCheckerOption func(*ReadyChecker) @@ -94,6 +101,9 @@ func (c *ReadyChecker) IsReady(ctx context.Context, v *resource.Info) (bool, err case *corev1.Pod: pod, err := c.client.CoreV1().Pods(v.Namespace).Get(ctx, v.Name, metav1.GetOptions{}) if err != nil || !c.isPodReady(pod) { + if err == nil { + err = c.getPodFailedError(pod) + } return false, err } case *batchv1.Job: @@ -204,6 +214,40 @@ func (c *ReadyChecker) IsReady(ctx context.Context, v *resource.Info) (bool, err return true, nil } +func (c *ReadyChecker) getPodFailedError(pod *corev1.Pod) error { + podErrors := make([]PodError, 0) + if pod.Status.Phase == corev1.PodFailed { + containerStatuses := pod.Status.ContainerStatuses + if pod.Status.InitContainerStatuses != nil { + containerStatuses = append(containerStatuses, pod.Status.InitContainerStatuses...) + } + + for _, cs := range containerStatuses { + if cs.State.Terminated != nil { + podErrors = append(podErrors, PodError{ + PodName: pod.Name, + Container: cs.Name, + Reason: cs.State.Terminated.Reason, + Message: cs.State.Terminated.Message, + }) + } else if cs.State.Waiting != nil { + podErrors = append(podErrors, PodError{ + PodName: pod.Name, + Container: cs.Name, + Reason: cs.State.Waiting.Reason, + Message: cs.State.Waiting.Message, + }) + } + } + } + + if len(podErrors) > 0 { + return fmt.Errorf("%+v", podErrors) + } + + return nil +} + func (c *ReadyChecker) podsReadyForObject(ctx context.Context, namespace string, obj runtime.Object) (bool, error) { pods, err := c.podsforObject(ctx, namespace, obj) if err != nil { diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index 36110d0de..e88c3185c 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -63,6 +63,7 @@ func (w *waiter) waitForResources(created ResourceList) error { ready, err := w.c.IsReady(ctx, v) if waitRetries > 0 && w.isRetryableError(err, v) { + waitRetries-- numberOfErrors[i]++ if numberOfErrors[i] > waitRetries { w.log("Max number of retries reached")