From 56fc24668f56a2116e090dbe8058d2bafa68eb99 Mon Sep 17 00:00:00 2001 From: Suleiman Dibirov Date: Wed, 19 Jun 2024 21:29:47 +0300 Subject: [PATCH] fixed output and completed pod phase Signed-off-by: Suleiman Dibirov --- pkg/kube/ready.go | 83 ++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/pkg/kube/ready.go b/pkg/kube/ready.go index e7ba5786c..797e74d14 100644 --- a/pkg/kube/ready.go +++ b/pkg/kube/ready.go @@ -19,7 +19,9 @@ package kube // import "helm.sh/helm/v3/pkg/kube" import ( "context" "fmt" + "strings" + "github.com/hashicorp/go-multierror" appsv1 "k8s.io/api/apps/v1" appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta2 "k8s.io/api/apps/v1beta2" @@ -38,13 +40,6 @@ 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) @@ -100,12 +95,11 @@ func (c *ReadyChecker) IsReady(ctx context.Context, v *resource.Info) (bool, err switch value := AsVersioned(v).(type) { 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) - } + if err != nil { return false, err } + ready, err := c.isPodReady(pod) + return ready, err case *batchv1.Job: if c.checkJobs { job, err := c.client.BatchV1().Jobs(v.Namespace).Get(ctx, v.Name, metav1.GetOptions{}) @@ -215,7 +209,7 @@ func (c *ReadyChecker) IsReady(ctx context.Context, v *resource.Info) (bool, err } func (c *ReadyChecker) getPodFailedError(pod *corev1.Pod) error { - podErrors := make([]podError, 0) + var err error if pod.Status.Phase == corev1.PodFailed { containerStatuses := pod.Status.ContainerStatuses if pod.Status.InitContainerStatuses != nil { @@ -224,28 +218,32 @@ func (c *ReadyChecker) getPodFailedError(pod *corev1.Pod) error { 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, - }) + err = multierror.Append( + err, + fmt.Errorf( + "pod: %q, container: %q. reason: %q. message: %q", + pod.Name, + cs.Name, + cs.State.Terminated.Reason, + strings.TrimSpace(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, - }) + err = multierror.Append( + err, + fmt.Errorf( + "pod: %q, container: %q. reason: %q. message: %q", + pod.Name, + cs.Name, + cs.State.Waiting.Reason, + strings.TrimSpace(cs.State.Waiting.Message), + ), + ) } } } - if len(podErrors) > 0 { - return fmt.Errorf("%+v", podErrors) - } - - return nil + return err } func (c *ReadyChecker) podsReadyForObject(ctx context.Context, namespace string, obj runtime.Object) (bool, error) { @@ -254,8 +252,8 @@ func (c *ReadyChecker) podsReadyForObject(ctx context.Context, namespace string, return false, err } for _, pod := range pods { - if !c.isPodReady(&pod) { - return false, nil + if isReady, err := c.isPodReady(&pod); !isReady { + return false, err } } return true, nil @@ -270,15 +268,26 @@ func (c *ReadyChecker) podsforObject(ctx context.Context, namespace string, obj return list, err } -// isPodReady returns true if a pod is ready; false otherwise. -func (c *ReadyChecker) isPodReady(pod *corev1.Pod) bool { - for _, c := range pod.Status.Conditions { - if c.Type == corev1.PodReady && c.Status == corev1.ConditionTrue { - return true +// isPodReady returns true if the pod is ready, false if it is not ready, and an error if the pod is in a failed state. +func (c *ReadyChecker) isPodReady(pod *corev1.Pod) (bool, error) { + if pod.Status.Phase == corev1.PodSucceeded { + return true, nil + } + + err := c.getPodFailedError(pod) + if err != nil { + c.log("Pod is failed: %s/%s", pod.GetNamespace(), pod.GetName()) + return false, err + } + + for _, condition := range pod.Status.Conditions { + if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue { + return true, nil } } + c.log("Pod is not ready: %s/%s", pod.GetNamespace(), pod.GetName()) - return false + return false, nil } func (c *ReadyChecker) jobReady(job *batchv1.Job) (bool, error) {