diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a3c92cae..16d8a1c05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). ### Added - Added the option to disable prometheus service monitor creation [#810](https://github.com/NVIDIA/KAI-Scheduler/pull/810) [itsomri](https://github.com/itsomri) +### Fixed +- Fixed pod controller logging to use request namespace/name instead of empty pod object fields when pod is not found + ## [v0.12.0] - 2025-12-24 ### Added diff --git a/pkg/podgrouper/pod_controller.go b/pkg/podgrouper/pod_controller.go index bf06dd528..a40484e37 100644 --- a/pkg/podgrouper/pod_controller.go +++ b/pkg/podgrouper/pod_controller.go @@ -75,7 +75,7 @@ func (r *PodReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.R err := r.Client.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: req.Name}, &pod) if err != nil { if errors.IsNotFound(err) { - logger.V(1).Info(fmt.Sprintf("Pod %s/%s not found, was probably deleted", pod.Namespace, pod.Name)) + logger.V(1).Info(fmt.Sprintf("Pod %s/%s not found, was probably deleted", req.Namespace, req.Name)) return ctrl.Result{}, nil } diff --git a/pkg/podgrouper/pod_controller_test.go b/pkg/podgrouper/pod_controller_test.go index 60516e3ce..1e2d46b3b 100644 --- a/pkg/podgrouper/pod_controller_test.go +++ b/pkg/podgrouper/pod_controller_test.go @@ -4,10 +4,12 @@ package controllers import ( + "bytes" "context" "fmt" "testing" + "github.com/go-logr/logr" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -18,11 +20,39 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/log" "github.com/NVIDIA/KAI-scheduler/pkg/common/constants" "github.com/NVIDIA/KAI-scheduler/pkg/podgrouper/podgroup" ) +type testLogSink struct { + buffer *bytes.Buffer +} + +func (s *testLogSink) Init(info logr.RuntimeInfo) {} +func (s *testLogSink) Enabled(level int) bool { return true } +func (s *testLogSink) Info(level int, msg string, keysAndValues ...interface{}) { + s.buffer.WriteString(fmt.Sprintf("[%d] %s", level, msg)) + for i := 0; i < len(keysAndValues); i += 2 { + if i+1 < len(keysAndValues) { + s.buffer.WriteString(fmt.Sprintf(" %v=%v", keysAndValues[i], keysAndValues[i+1])) + } + } + s.buffer.WriteString("\n") +} +func (s *testLogSink) Error(err error, msg string, keysAndValues ...interface{}) { + s.buffer.WriteString(fmt.Sprintf("ERROR %s: %v", msg, err)) + for i := 0; i < len(keysAndValues); i += 2 { + if i+1 < len(keysAndValues) { + s.buffer.WriteString(fmt.Sprintf(" %v=%v", keysAndValues[i], keysAndValues[i+1])) + } + } + s.buffer.WriteString("\n") +} +func (s *testLogSink) WithValues(keysAndValues ...interface{}) logr.LogSink { return s } +func (s *testLogSink) WithName(name string) logr.LogSink { return s } + const nodePoolKey = "kai.scheduler/node-pool" func TestAddNodePoolLabel(t *testing.T) { @@ -284,3 +314,41 @@ func TestLabelsMatch(t *testing.T) { }) } } + +func TestReconcilePodNotFound(t *testing.T) { + testNamespace := "test-namespace" + testPodName := "test-pod" + + var logBuffer bytes.Buffer + ctx := log.IntoContext(context.TODO(), logr.New(&testLogSink{buffer: &logBuffer})) + fakeClient := fake.NewClientBuilder().Build() + + reconciler := PodReconciler{ + Client: fakeClient, + Scheme: scheme.Scheme, + podGrouper: &fakePodGrouper{}, + PodGroupHandler: nil, + configs: Configs{ + SchedulerName: "kai-scheduler", + }, + eventRecorder: record.NewFakeRecorder(10), + } + + result, err := reconciler.Reconcile(ctx, ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: testNamespace, + Name: testPodName, + }, + }) + + assert.NoError(t, err) + assert.Equal(t, ctrl.Result{}, result) + + logOutput := logBuffer.String() + expectedPattern := fmt.Sprintf("Pod %s/%s not found", testNamespace, testPodName) + + assert.Contains(t, logOutput, expectedPattern, + "Log should contain correct namespace/name from req, got: %s", logOutput) + assert.NotContains(t, logOutput, "Pod / not found", + "Log should not contain empty namespace/name pattern") +}