diff --git a/pkg/pod/status.go b/pkg/pod/status.go index 082201797a0..2a1ba103d05 100644 --- a/pkg/pod/status.go +++ b/pkg/pod/status.go @@ -53,6 +53,9 @@ const ( // to resource constraints on the node ReasonExceededNodeResources = "ExceededNodeResources" + // ReasonPullImageFailed indicates that the TaskRun's pod failed to pull image + ReasonPullImageFailed = "PullImageFailed" + // ReasonCreateContainerConfigError indicates that the TaskRun failed to create a pod due to // config error of container ReasonCreateContainerConfigError = "CreateContainerConfigError" @@ -314,6 +317,8 @@ func updateIncompleteTaskRunStatus(trs *v1beta1.TaskRunStatus, pod *corev1.Pod) markStatusRunning(trs, ReasonExceededNodeResources, "TaskRun Pod exceeded available resources") case isPodHitConfigError(pod): markStatusFailure(trs, ReasonCreateContainerConfigError, "Failed to create pod due to config error") + case isPullImageError(pod): + markStatusRunning(trs, ReasonPullImageFailed, getWaitingMessage(pod)) default: markStatusRunning(trs, ReasonPending, getWaitingMessage(pod)) } @@ -408,6 +413,34 @@ func isPodHitConfigError(pod *corev1.Pod) bool { return false } +// isPullImageError returns true if the Pod's status indicates there are any error when pulling image +func isPullImageError(pod *corev1.Pod) bool { + for _, containerStatus := range pod.Status.ContainerStatuses { + if containerStatus.State.Waiting != nil && isImageErrorReason(containerStatus.State.Waiting.Reason) { + return true + } + } + return false +} + +func isImageErrorReason(reason string) bool { + // Reference from https://github.com/kubernetes/kubernetes/blob/a1c8e9386af844757333733714fa1757489735b3/pkg/kubelet/images/types.go#L26 + imageErrorReasons := []string{ + "ImagePullBackOff", + "ImageInspectError", + "ErrImagePull", + "ErrImageNeverPull", + "RegistryUnavailable", + "InvalidImageName", + } + for _, imageReason := range imageErrorReasons { + if imageReason == reason { + return true + } + } + return false +} + func getWaitingMessage(pod *corev1.Pod) string { // First, try to surface reason for pending/unknown about the actual build step. for _, status := range pod.Status.ContainerStatuses { diff --git a/pkg/pod/status_test.go b/pkg/pod/status_test.go index 6cbdb0f85a2..006f76ae215 100644 --- a/pkg/pod/status_test.go +++ b/pkg/pod/status_test.go @@ -988,6 +988,46 @@ func TestMakeTaskRunStatus(t *testing.T) { CompletionTime: &metav1.Time{Time: time.Now()}, }, }, + }, { + desc: "when pod is pending because of pulling image then the error should bubble up to taskrun status", + pod: corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pod", + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{{ + Name: "step-first", + }}, + }, + Status: corev1.PodStatus{ + Phase: corev1.PodPending, + ContainerStatuses: []corev1.ContainerStatus{{ + Name: "step-first", + State: corev1.ContainerState{ + Waiting: &corev1.ContainerStateWaiting{ + Reason: "ImagePullBackOff", + Message: "Back-off pulling image xxxxxxx", + }, + }, + }}, + }, + }, + want: v1beta1.TaskRunStatus{ + Status: statusPending("PullImageFailed", `build step "step-first" is pending with reason "Back-off pulling image xxxxxxx"`), + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + Steps: []v1beta1.StepState{{ + ContainerState: corev1.ContainerState{ + Waiting: &corev1.ContainerStateWaiting{ + Reason: "ImagePullBackOff", + Message: "Back-off pulling image xxxxxxx", + }, + }, + Name: "first", + ContainerName: "step-first", + }}, + Sidecars: []v1beta1.SidecarState{}, + }, + }, }} { t.Run(c.desc, func(t *testing.T) { now := metav1.Now()