Repository: kubernetes-sigs/kernel-module-management
Pull request #1048: Updating image puller package with the new pod flow
Author: login: yevgeny-shnaidman
Labels: name: size/L
description: Denotes a PR that changes 100-499 lines, ignoring generated files.
name: approved
description: Indicates a PR has been approved by an approver from all required OWNERS files.
name: lgtm
description: "Looks good to me", indicates that a PR is ready to be merged.
name: cncf-cla: yes
description: Indicates the PR's author has signed the CNCF CLA.
Created: 2025-03-11T16:23:37Z | Merged: 2025-03-12T11:45:46Z

This commit contains the following changes:
1. Removing image label - image will be obtained from the Spec directly
2. Adding pod type label - one-time pod that should be considered as Failed once the container fails on image pull, and run-until-success, that is considered as InProgess, in case container ails on image pull
3. Adding GetPodStatus API - this api returns pod status based on the following:
   - the pod that fails to pull image stays in the Pending state, and the container status is updated with appropriate reason.So, if the pod is one-time pod, and container failed on image pull - status is Failed. Otherwise status is Running, since we let the pod restart the container with back-offs
4. Pod is created with restartPolicy Never, since if the pod managed to pull image - we consider it a success


Diff:
diff --git a/internal/pod/imagepuller.go b/internal/pod/imagepuller.go
index 060f76b3c..874016b7b 100644
--- a/internal/pod/imagepuller.go
+++ b/internal/pod/imagepuller.go
@@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
+
+	moduleImageLabelKey = "kmm.node.kubernetes.io/module-image-config"
+	pullPodTypeLabelKey = "kmm.node.kubernetes.io/pull-pod-type"
+
+	pullerContainerName = "puller"
+
+	pullPodTypeOneTime  = "one-time-pull"
+	pullPodUntilSuccess = "until-success"
+)
+
 //go:generate mockgen -source=imagepuller.go -package=pod -destination=mock_imagepuller.go
 
 type ImagePuller interface {
@@ -20,14 +40,9 @@ type ImagePuller interface {
 	ListPullPods(ctx context.Context, micObj *kmmv1beta1.ModuleImagesConfig) ([]v1.Pod, error)
 	GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod
 	GetPullPodImage(pod v1.Pod) string
+	GetPullPodStatus(pod *v1.Pod) PullPodStatus
 }
 
-const (
-	moduleImageLabelKey = "kmm.node.kubernetes.io/module-image-config"
-	imageLabelKey       = "kmm.node.kubernetes.io/module-image"
-	pullerContainerName = "puller"
-)
-
 type imagePullerImpl struct {
 	client client.Client
 	scheme *runtime.Scheme
@@ -43,9 +58,9 @@ func NewImagePuller(client client.Client, scheme *runtime.Scheme) ImagePuller {
 func (ipi *imagePullerImpl) CreatePullPod(ctx context.Context, imageSpec *kmmv1beta1.ModuleImageSpec,
 	micObj *kmmv1beta1.ModuleImagesConfig) error {
 
-	restartPolicy := v1.RestartPolicyOnFailure
+	pullPodTypeLabeValue := pullPodUntilSuccess
 	if imageSpec.Build != nil || imageSpec.Sign != nil {
-		restartPolicy = v1.RestartPolicyNever
+		pullPodTypeLabeValue = pullPodTypeOneTime
 	}
 
 	imagePullSecrets := []v1.LocalObjectReference{}
@@ -59,7 +74,7 @@ func (ipi *imagePullerImpl) CreatePullPod(ctx context.Context, imageSpec *kmmv1b
 			Namespace:    micObj.Namespace,
 			Labels: map[string]string{
 				moduleImageLabelKey: micObj.Name,
-				imageLabelKey:       imageSpec.Image,
+				pullPodTypeLabelKey: pullPodTypeLabeValue,
 			},
 		},
 		Spec: v1.PodSpec{
@@ -70,7 +85,7 @@ func (ipi *imagePullerImpl) CreatePullPod(ctx context.Context, imageSpec *kmmv1b
 					Command: []string{"/bin/sh", "-c", "exit 0"},
 				},
 			},
-			RestartPolicy:    restartPolicy,
+			RestartPolicy:    v1.RestartPolicyNever,
 			ImagePullSecrets: imagePullSecrets,
 		},
 	}
@@ -92,7 +107,7 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 
 	pl := v1.PodList{}
 
-	hl := client.HasLabels{imageLabelKey}
+	hl := client.HasLabels{pullPodTypeLabelKey}
 	ml := client.MatchingLabels{moduleImageLabelKey: micObj.Name}
 
 	ctrl.LoggerFrom(ctx).WithValues("mic name", micObj.Name).V(1).Info("Listing mic image Pods")
@@ -107,7 +122,7 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
@@ -115,5 +130,38 @@ func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
+			return PullImageInProcess
+		}
+
+		pullPodType := pod.GetLabels()[pullPodTypeLabelKey]
+		// if pod is targeted to wait till the end - return the InProgress
+		if pullPodType == pullPodUntilSuccess {
+			return PullImageInProcess
+		}
+
+		if waitingReason := pod.Status.ContainerStatuses[0].State.Waiting.Reason; waitingReason == imagePullBackOffReason || waitingReason == errImagePullReason {
+			return PullImageFailed
+		}
+	}
+
+	return PullImageUnexpectedErr
 }
diff --git a/internal/pod/imagepuller_test.go b/internal/pod/imagepuller_test.go
index fae838401..92c9ac57c 100644
--- a/internal/pod/imagepuller_test.go
+++ b/internal/pod/imagepuller_test.go
@@ -38,7 +38,7 @@ var _ = Describe("ListPullPods", func() {
 	}
 
 	It("list succeeded", func() {
-		hl := ctrlclient.HasLabels{imageLabelKey}
+		hl := ctrlclient.HasLabels{pullPodTypeLabelKey}
 		ml := ctrlclient.MatchingLabels{moduleImageLabelKey: testMic.Name}
 
 		clnt.EXPECT().List(context.Background(), gomock.Any(), ctrlclient.InNamespace(testMic.Namespace), hl, ml).DoAndReturn(
@@ -54,7 +54,7 @@ var _ = Describe("ListPullPods", func() {
 	})
 
 	It("list failed", func() {
-		hl := ctrlclient.HasLabels{imageLabelKey}
+		hl := ctrlclient.HasLabels{pullPodTypeLabelKey}
 		ml := ctrlclient.MatchingLabels{moduleImageLabelKey: testMic.Name}
 
 		clnt.EXPECT().List(context.Background(), gomock.Any(), ctrlclient.InNamespace(testMic.Namespace), hl, ml).Return(fmt.Errorf("some error"))
@@ -116,13 +116,21 @@ var _ = Describe("GetPullPodForImage", func() {
 
 	pullPods := []v1.Pod{
 		{
-			ObjectMeta: metav1.ObjectMeta{
-				Labels: map[string]string{imageLabelKey: "image 1"},
+			Spec: v1.PodSpec{
+				Containers: []v1.Container{
+					{
+						Image: "image 1",
+					},
+				},
 			},
 		},
 		{
-			ObjectMeta: metav1.ObjectMeta{
-				Labels: map[string]string{imageLabelKey: "image 2"},
+			Spec: v1.PodSpec{
+				Containers: []v1.Container{
+					{
+						Image: "image 2",
+					},
+				},
 			},
 		},
 	}
@@ -130,7 +138,7 @@ var _ = Describe("GetPullPodForImage", func() {
 	It("there is a pull pod for that image", func() {
 		res := ip.GetPullPodForImage(pullPods, "image 2")
 		Expect(res).ToNot(BeNil())
-		Expect(res.Labels[imageLabelKey]).To(Equal("image 2"))
+		Expect(res.Spec.Containers[0].Image).To(Equal("image 2"))
 	})
 
 	It("there is no pull pod for that image", func() {
@@ -170,7 +178,7 @@ var _ = Describe("CreatePullPod", func() {
 				Namespace:    testMic.Namespace,
 				Labels: map[string]string{
 					moduleImageLabelKey: "some name",
-					imageLabelKey:       "some image",
+					pullPodTypeLabelKey: pullPodUntilSuccess,
 				},
 			},
 			Spec: v1.PodSpec{
@@ -181,7 +189,7 @@ var _ = Describe("CreatePullPod", func() {
 						Command: []string{"/bin/sh", "-c", "exit 0"},
 					},
 				},
-				RestartPolicy:    v1.RestartPolicyOnFailure,
+				RestartPolicy:    v1.RestartPolicyNever,
 				ImagePullSecrets: []v1.LocalObjectReference{},
 			},
 		}
@@ -202,3 +210,82 @@ var _ = Describe("CreatePullPod", func() {
 		Expect(err).To(BeNil())
 	})
 })
+
+var _ = Describe("GetPullPodStatus", func() {
+	var (
+		ctrl *gomock.Controller
+		clnt *client.MockClient
+		ip   ImagePuller
+	)
+
+	BeforeEach(func() {
+		ctrl = gomock.NewController(GinkgoT())
+		clnt = client.NewMockClient(ctrl)
+		ip = NewImagePuller(clnt, scheme)
+	})
+
+	testPod := v1.Pod{
+		Status: v1.PodStatus{
+			Phase: v1.PodSucceeded,
+		},
+	}
+
+	It("check different phases except for PodPending", func() {
+		By("phase Succeeded")
+
+		res := ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageSuccess))
+
+		By("phase PodFailed")
+		testPod.Status.Phase = v1.PodFailed
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageUnexpectedErr))
+
+		By("phase PodUnknown")
+		testPod.Status.Phase = v1.PodUnknown
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageUnexpectedErr))
+
+		By("phase PodRunning")
+		testPod.Status.Phase = v1.PodRunning
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageInProcess))
+	})
+
+	It("check container statuses for PodPending", func() {
+		testPod.Status.Phase = v1.PodPending
+		By("container statuses missing")
+		testPod.Status.ContainerStatuses = nil
+		res := ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageInProcess))
+
+		By("container statuses waiting is nil")
+		testPod.Status.ContainerStatuses = []v1.ContainerStatus{v1.ContainerStatus{}}
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageInProcess))
+
+		By("container statuses waiting is not nil and pod is not one time pull pod")
+		testPod.SetLabels(map[string]string{pullPodTypeLabelKey: pullPodUntilSuccess})
+		testPod.Status.ContainerStatuses[0].State = v1.ContainerState{
+			Waiting: &v1.ContainerStateWaiting{},
+		}
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageInProcess))
+
+		By("container statuses waiting is not nil and pod is one time pull pod and reason is not image pull error")
+		testPod.SetLabels(map[string]string{pullPodTypeLabelKey: pullPodTypeOneTime})
+		testPod.Status.ContainerStatuses[0].State.Waiting.Reason = "some reason"
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageUnexpectedErr))
+
+		By("container statuses waiting is not nil and pod is one time pull pod and reason is ImagePullBackOff")
+		testPod.Status.ContainerStatuses[0].State.Waiting.Reason = imagePullBackOffReason
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageFailed))
+
+		By("container statuses waiting is not nil and pod is one time pull pod and reason is errImagePullReason")
+		testPod.Status.ContainerStatuses[0].State.Waiting.Reason = errImagePullReason
+		res = ip.GetPullPodStatus(&testPod)
+		Expect(res).To(Equal(PullImageFailed))
+	})
+})
diff --git a/internal/pod/mock_imagepuller.go b/internal/pod/mock_imagepuller.go
index 16de2b147..dc8a77c00 100644
--- a/internal/pod/mock_imagepuller.go
+++ b/internal/pod/mock_imagepuller.go
@@ -96,6 +96,20 @@ func (mr *MockImagePullerMockRecorder) GetPullPodImage(pod any) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPullPodImage", reflect.TypeOf((*MockImagePuller)(nil).GetPullPodImage), pod)
 }
 
+// GetPullPodStatus mocks base method.
+func (m *MockImagePuller) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetPullPodStatus", pod)
+	ret0, _ := ret[0].(PullPodStatus)
+	return ret0
+}
+
+// GetPullPodStatus indicates an expected call of GetPullPodStatus.
+func (mr *MockImagePullerMockRecorder) GetPullPodStatus(pod any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPullPodStatus", reflect.TypeOf((*MockImagePuller)(nil).GetPullPodStatus), pod)
+}
+
 // ListPullPods mocks base method.
 func (m *MockImagePuller) ListPullPods(ctx context.Context, micObj *v1beta1.ModuleImagesConfig) ([]v1.Pod, error) {
 	m.ctrl.T.Helper()


Reviews:
user: login: TomerNewman
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-12T08:49:50Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:24:22Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:24:26Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:29:11Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:32:55Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:38:07Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:46:46Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:47:42Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:48:11Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:49:35Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T10:50:59Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:06:08Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:07:46Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:07:59Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:08:51Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:10:43Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:14:28Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:17:15Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:18:15Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:19:02Z
user: login: yevgeny-shnaidman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:20:36Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:25:49Z
user: login: ybettan
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T11:45:50Z

Review comments:
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
path: internal/pod/imagepuller.go
user: login: TomerNewman
body: A question, I see that when we go to this line we assume already `ContainerStatuses` is not nil, but can it be an empty slice? and if not, can we assume `State` has already `Waiting` initialized?
created_at: 2025-03-12T08:49:43Z
author_association: COLLABORATOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
+
+	moduleImageLabelKey = "kmm.node.kubernetes.io/module-image-config"
+	pullPodTypeLabelKey = "kmm.node.kubernetes.io/pull-pod-type"
+
+	pullerContainerName = "puller"
+
+	pullPodTypeOneTime  = "one-time-pull"
+	pullPodUntilSuccess = "until-success"
path: internal/pod/imagepuller.go
user: login: ybettan
body: How about we enum those as well?
created_at: 2025-03-12T10:24:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
path: internal/pod/imagepuller.go
user: login: ybettan
body: How about we enum those as well?
created_at: 2025-03-12T10:24:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,9 +58,9 @@ func NewImagePuller(client client.Client, scheme *runtime.Scheme) ImagePuller {
 func (ipi *imagePullerImpl) CreatePullPod(ctx context.Context, imageSpec *kmmv1beta1.ModuleImageSpec,
 	micObj *kmmv1beta1.ModuleImagesConfig) error {
 
-	restartPolicy := v1.RestartPolicyOnFailure
+	pullPodTypeLabeValue := pullPodUntilSuccess
 	if imageSpec.Build != nil || imageSpec.Sign != nil {
-		restartPolicy = v1.RestartPolicyNever
+		pullPodTypeLabeValue = pullPodTypeOneTime
path: internal/pod/imagepuller.go
user: login: ybettan
body: Shouldn't it be the opposite? That we run once if there are not build/sign and continue trying if we can build?
created_at: 2025-03-12T10:29:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
path: internal/pod/imagepuller.go
user: login: ybettan
body: Do we really need this public method? It doesn't give us anything that we can have access to in a single like outside of this package.
created_at: 2025-03-12T10:32:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
+			return PullImageInProcess
+		}
+
+		pullPodType := pod.GetLabels()[pullPodTypeLabelKey]
+		// if pod is targeted to wait till the end - return the InProgress
+		if pullPodType == pullPodUntilSuccess {
+			return PullImageInProcess
+		}
+
+		if pod.Status.ContainerStatuses[0].State.Waiting.Reason == imagePullBackOffReason ||
+			pod.Status.ContainerStatuses[0].State.Waiting.Reason == errImagePullReason {
+			return PullImageFailed
+		}
path: internal/pod/imagepuller.go
user: login: ybettan
body: ```suggestion
		if waitingReason := pod.Status.ContainerStatuses[0].State.Waiting.Reason; waitingReason == imagePullBackOffReason || waitingReason == errImagePullReason {
			return PullImageFailed
		}
```
created_at: 2025-03-12T10:38:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: it won't be an empty slice - the slice is created once the there is at least one container status available.  We cannot assume that Waiting is not nil. Waiting will be initializes only in case container status is in waiting state
created_at: 2025-03-12T10:46:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
+
+	moduleImageLabelKey = "kmm.node.kubernetes.io/module-image-config"
+	pullPodTypeLabelKey = "kmm.node.kubernetes.io/pull-pod-type"
+
+	pullerContainerName = "puller"
+
+	pullPodTypeOneTime  = "one-time-pull"
+	pullPodUntilSuccess = "until-success"
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: they are just values for the labels, so i don't see any need to define a type for them
created_at: 2025-03-12T10:47:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: Those are also just values of the reason field inside container statuses
created_at: 2025-03-12T10:48:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,9 +58,9 @@ func NewImagePuller(client client.Client, scheme *runtime.Scheme) ImagePuller {
 func (ipi *imagePullerImpl) CreatePullPod(ctx context.Context, imageSpec *kmmv1beta1.ModuleImageSpec,
 	micObj *kmmv1beta1.ModuleImagesConfig) error {
 
-	restartPolicy := v1.RestartPolicyOnFailure
+	pullPodTypeLabeValue := pullPodUntilSuccess
 	if imageSpec.Build != nil || imageSpec.Sign != nil {
-		restartPolicy = v1.RestartPolicyNever
+		pullPodTypeLabeValue = pullPodTypeOneTime
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: actually  - no. In case there is a buld/sign present, then once the pull fails, we can stop trying to pull and go to building/signing images. In case there are no build/sign, then we need to try the pulling indefinitly
created_at: 2025-03-12T10:49:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: image puller hides the implementation of the pull pod from the calling layer (in this case MBSC). Why should MBSC care about the details of how to get the status from pod?
created_at: 2025-03-12T10:50:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
+			return PullImageInProcess
+		}
+
+		pullPodType := pod.GetLabels()[pullPodTypeLabelKey]
+		// if pod is targeted to wait till the end - return the InProgress
+		if pullPodType == pullPodUntilSuccess {
+			return PullImageInProcess
+		}
+
+		if pod.Status.ContainerStatuses[0].State.Waiting.Reason == imagePullBackOffReason ||
+			pod.Status.ContainerStatuses[0].State.Waiting.Reason == errImagePullReason {
+			return PullImageFailed
+		}
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: Fixed
created_at: 2025-03-12T11:06:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
+
+	moduleImageLabelKey = "kmm.node.kubernetes.io/module-image-config"
+	pullPodTypeLabelKey = "kmm.node.kubernetes.io/pull-pod-type"
+
+	pullerContainerName = "puller"
+
+	pullPodTypeOneTime  = "one-time-pull"
+	pullPodUntilSuccess = "until-success"
path: internal/pod/imagepuller.go
user: login: ybettan
body: If those are the only 2 values allowed for this label, then I think it should be validated through enums. 
created_at: 2025-03-12T11:07:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
path: internal/pod/imagepuller.go
user: login: ybettan
body: If those are the only 2 values allowed for this label, then I think it should be validated through enums.
created_at: 2025-03-12T11:07:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,9 +58,9 @@ func NewImagePuller(client client.Client, scheme *runtime.Scheme) ImagePuller {
 func (ipi *imagePullerImpl) CreatePullPod(ctx context.Context, imageSpec *kmmv1beta1.ModuleImageSpec,
 	micObj *kmmv1beta1.ModuleImagesConfig) error {
 
-	restartPolicy := v1.RestartPolicyOnFailure
+	pullPodTypeLabeValue := pullPodUntilSuccess
 	if imageSpec.Build != nil || imageSpec.Sign != nil {
-		restartPolicy = v1.RestartPolicyNever
+		pullPodTypeLabeValue = pullPodTypeOneTime
path: internal/pod/imagepuller.go
user: login: ybettan
body: Ohh right, and then we update the MIC status based on the MBSC status and not based on the pull pods.
created_at: 2025-03-12T11:08:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
path: internal/pod/imagepuller.go
user: login: ybettan
body: We are not getting the status from the pod but the image from the spec. If you prefer to keep it as is I don't mind but you know how I feel about primitive getters/setters :) 
created_at: 2025-03-12T11:10:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,46 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
+			return PullImageInProcess
+		}
+
+		pullPodType := pod.GetLabels()[pullPodTypeLabelKey]
+		// if pod is targeted to wait till the end - return the InProgress
+		if pullPodType == pullPodUntilSuccess {
+			return PullImageInProcess
path: internal/pod/imagepuller.go
user: login: ybettan
body: How will the customer knows that he forgot to push the image for example if we return a "in-progress" value. Shouldnt we return a better status for him to understand that he forgot to push the image?
created_at: 2025-03-12T11:14:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
+
+	moduleImageLabelKey = "kmm.node.kubernetes.io/module-image-config"
+	pullPodTypeLabelKey = "kmm.node.kubernetes.io/pull-pod-type"
+
+	pullerContainerName = "puller"
+
+	pullPodTypeOneTime  = "one-time-pull"
+	pullPodUntilSuccess = "until-success"
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: what do you mean by enums? in golang  it is just consts.  defining a type for a label value will means conversions, which will make the code harder to read
created_at: 2025-03-12T11:17:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -12,6 +12,26 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 )
 
+type PullPodStatus string
+
+const (
+	PullImageFailed        PullPodStatus = "pullFailed"
+	PullImageSuccess       PullPodStatus = "pullSuccess"
+	PullImageInProcess     PullPodStatus = "pullInProcess"
+	PullImageUnexpectedErr PullPodStatus = "unexpectedError"
+
+	imagePullBackOffReason = "ImagePullBackOff"
+	errImagePullReason     = "ErrImagePull"
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: same answer as above, and besides that there can be additional values to the reason string, but we want to check only those 2
created_at: 2025-03-12T11:18:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,47 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: sorry, my mistake! It makes the code simplier in the mbsc controller
created_at: 2025-03-12T11:19:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,46 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
+			return PullImageInProcess
+		}
+
+		pullPodType := pod.GetLabels()[pullPodTypeLabelKey]
+		// if pod is targeted to wait till the end - return the InProgress
+		if pullPodType == pullPodUntilSuccess {
+			return PullImageInProcess
path: internal/pod/imagepuller.go
user: login: yevgeny-shnaidman
body: we can add a more explanatory value into the MBSC status ("image is being pulled"), but it should not be in this package
created_at: 2025-03-12T11:20:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,46 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
+			return PullImageInProcess
+		}
+
+		pullPodType := pod.GetLabels()[pullPodTypeLabelKey]
+		// if pod is targeted to wait till the end - return the InProgress
+		if pullPodType == pullPodUntilSuccess {
+			return PullImageInProcess
path: internal/pod/imagepuller.go
user: login: ybettan
body: But there is no MBSC involved here... this is just pending until the image is pulled (and if the user has forgot to push then until he does that).
created_at: 2025-03-12T11:25:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -107,13 +122,46 @@ func (ipi *imagePullerImpl) ListPullPods(ctx context.Context, micObj *kmmv1beta1
 func (ipi *imagePullerImpl) GetPullPodForImage(pods []v1.Pod, image string) *v1.Pod {
 
 	for i, pod := range pods {
-		if image == pod.Labels[imageLabelKey] {
+		if image == pod.Spec.Containers[0].Image {
 			return &pods[i]
 		}
 	}
 	return nil
 }
 
 func (ipi *imagePullerImpl) GetPullPodImage(pod v1.Pod) string {
-	return pod.Labels[imageLabelKey]
+	return pod.Spec.Containers[0].Image
+}
+
+func (ipi *imagePullerImpl) GetPullPodStatus(pod *v1.Pod) PullPodStatus {
+	switch pod.Status.Phase {
+	case v1.PodSucceeded:
+		return PullImageSuccess
+	case v1.PodFailed, v1.PodUnknown:
+		return PullImageUnexpectedErr
+	case v1.PodRunning:
+		return PullImageInProcess
+	case v1.PodPending:
+		// no container statuses yet, the pod is just starting to pull images
+		if pod.Status.ContainerStatuses == nil {
+			return PullImageInProcess
+		}
+
+		// no wating status, the pull process is still in progress
+		if pod.Status.ContainerStatuses[0].State.Waiting == nil {
+			return PullImageInProcess
+		}
+
+		pullPodType := pod.GetLabels()[pullPodTypeLabelKey]
+		// if pod is targeted to wait till the end - return the InProgress
+		if pullPodType == pullPodUntilSuccess {
+			return PullImageInProcess
path: internal/pod/imagepuller.go
user: login: ybettan
body: We will merge it as is for now because the is the behavior in our current code and we will have a task to check if replacing it with `imageDoesNotExist` is a better option.
created_at: 2025-03-12T11:45:50Z
author_association: CONTRIBUTOR

PR comments:
user: login: k8s-ci-robot
created_at: 2025-03-11T16:23:43Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/kernel-module-management/pull/1048#" title="Author self-approved">yevgeny-shnaidman</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fkernel-module-management).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/kernel-module-management/blob/main/OWNERS)~~ [yevgeny-shnaidman]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: CONTRIBUTOR
user: login: netlify[bot]
created_at: 2025-03-11T16:24:00Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *kubernetes-sigs-kmm* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 717fe43f68757f045c452f378c744936463009cc |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/kubernetes-sigs-kmm/deploys/67d16e1a97000b000823b349 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-1048--kubernetes-sigs-kmm.netlify.app](https://deploy-preview-1048--kubernetes-sigs-kmm.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTEwNDgtLWt1YmVybmV0ZXMtc2lncy1rbW0ubmV0bGlmeS5hcHAifQ.ilAgag8ZvTnSJNgULkSK5vfXBr-CEquzcWq8AdPl6BU)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [kubernetes-sigs-kmm Preview](https://deploy-preview-1048--kubernetes-sigs-kmm.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/kubernetes-sigs-kmm/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: codecov-commenter
created_at: 2025-03-11T16:25:30Z
body: ## [Codecov](https://app.codecov.io/gh/kubernetes-sigs/kernel-module-management/pull/1048?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs) Report
Attention: Patch coverage is `93.75000%` with `2 lines` in your changes missing coverage. Please review.
> Project coverage is 74.49%. Comparing base [(`fa23a9b`)](https://app.codecov.io/gh/kubernetes-sigs/kernel-module-management/commit/fa23a9bea255d0cb4f71e727dc37862175f20bba?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs) to head [(`717fe43`)](https://app.codecov.io/gh/kubernetes-sigs/kernel-module-management/commit/717fe43f68757f045c452f378c744936463009cc?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs).
> Report is 235 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/kubernetes-sigs/kernel-module-management/pull/1048?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs) | Patch % | Lines |
|---|---|---|
| [internal/pod/imagepuller.go](https://app.codecov.io/gh/kubernetes-sigs/kernel-module-management/pull/1048?src=pr&el=tree&filepath=internal%2Fpod%2Fimagepuller.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs#diff-aW50ZXJuYWwvcG9kL2ltYWdlcHVsbGVyLmdv) | 93.75% | [2 Missing :warning: ](https://app.codecov.io/gh/kubernetes-sigs/kernel-module-management/pull/1048?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #1048      +/-   ##
==========================================
- Coverage   79.09%   74.49%   -4.61%     
==========================================
  Files          51       76      +25     
  Lines        5109     6736    +1627     
==========================================
+ Hits         4041     5018     +977     
- Misses        882     1510     +628     
- Partials      186      208      +22     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/kubernetes-sigs/kernel-module-management/pull/1048?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kubernetes-sigs).

<details><summary>🚀 New features to boost your workflow: </summary>

- ❄ [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: ybettan
created_at: 2025-03-12T10:22:13Z
body: > Adding pod type label - one-time pod that should be considered as Failed once the container fails on image pull, and run-until-success, that is considered as InProgess, in case container ails on image pull

Adding pod type label - one-time pod that should be considered as Failed once the container fails on image pull, and run-until-success, that is considered as InProgess, in case container ails on image pull and there are build instructions.
author_association: CONTRIBUTOR
user: login: ybettan
created_at: 2025-03-12T11:43:40Z
body: /lgtm
author_association: CONTRIBUTOR