From 467049c0f2f4a3f06310c35d676dd07e5b8a660f Mon Sep 17 00:00:00 2001 From: Mengxin Liu Date: Tue, 24 Feb 2026 03:14:56 +0000 Subject: [PATCH] fix: skip unallocated pods during IPAM initialization to avoid spurious errors During controller startup, InitIPAM() iterates over all pods and calls getPodKubeovnNets(), which checks namespace network annotations. However, namespace annotations are not yet set at this point because the namespace worker starts after InitIPAM(). This causes spurious error logs like "namespace kube-system network annotations is empty" for pods that have not been allocated an IP by kube-ovn (e.g., coredns on first startup). Skip pods without any allocated annotation before calling getPodKubeovnNets(), since they have no IP to restore into IPAM anyway. Signed-off-by: Mengxin Liu Co-Authored-By: Claude Opus 4.6 Signed-off-by: Mengxin Liu Co-authored-by: Cursor --- pkg/controller/init.go | 13 +++++++ pkg/controller/init_test.go | 76 +++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 pkg/controller/init_test.go diff --git a/pkg/controller/init.go b/pkg/controller/init.go index ad28963bb35..82d095e9a92 100644 --- a/pkg/controller/init.go +++ b/pkg/controller/init.go @@ -437,6 +437,10 @@ func (c *Controller) InitIPAM() error { continue } + if !hasAllocatedAnnotation(pod) { + continue + } + podNets, err := c.getPodKubeovnNets(pod) if err != nil { klog.Errorf("failed to get pod kubeovn nets %s.%s address %s: %v", pod.Name, pod.Namespace, pod.Annotations[util.IPAddressAnnotation], err) @@ -1034,3 +1038,12 @@ func (c *Controller) syncFinalizers() error { klog.Info("sync finalizers done") return nil } + +func hasAllocatedAnnotation(pod *v1.Pod) bool { + for key, value := range pod.Annotations { + if value == "true" && strings.HasSuffix(key, util.AllocatedAnnotationSuffix) { + return true + } + } + return false +} diff --git a/pkg/controller/init_test.go b/pkg/controller/init_test.go new file mode 100644 index 00000000000..485ad5ce740 --- /dev/null +++ b/pkg/controller/init_test.go @@ -0,0 +1,76 @@ +package controller + +import ( + "testing" + + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestHasAllocatedAnnotation(t *testing.T) { + tests := []struct { + name string + annotations map[string]string + expected bool + }{ + { + name: "nil annotations", + annotations: nil, + expected: false, + }, + { + name: "empty annotations", + annotations: map[string]string{}, + expected: false, + }, + { + name: "default provider allocated", + annotations: map[string]string{ + "ovn.kubernetes.io/allocated": "true", + }, + expected: true, + }, + { + name: "custom provider allocated", + annotations: map[string]string{ + "my-provider.kubernetes.io/allocated": "true", + }, + expected: true, + }, + { + name: "allocated is false", + annotations: map[string]string{ + "ovn.kubernetes.io/allocated": "false", + }, + expected: false, + }, + { + name: "unrelated annotations only", + annotations: map[string]string{ + "app": "test", + "ovn.kubernetes.io/ip_address": "10.0.0.1", + }, + expected: false, + }, + { + name: "multiple providers with one allocated", + annotations: map[string]string{ + "ovn.kubernetes.io/allocated": "false", + "my-provider.kubernetes.io/allocated": "true", + }, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pod := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: tt.annotations, + }, + } + require.Equal(t, tt.expected, hasAllocatedAnnotation(pod)) + }) + } +}