From 2ed7bb3d7aea5ddd1ce1b7fa7dea6ebaf0bb2dae Mon Sep 17 00:00:00 2001 From: Valerian Roche Date: Mon, 7 Jul 2025 21:30:53 -0400 Subject: [PATCH] Do not use transformer when fqdnTemplate is set --- source/pod.go | 62 +++++++------- source/pod_test.go | 201 +++++++++++++++++++++++++++++---------------- 2 files changed, 165 insertions(+), 98 deletions(-) diff --git a/source/pod.go b/source/pod.go index 7bcde5380..b996b358e 100644 --- a/source/pod.go +++ b/source/pod.go @@ -78,35 +78,39 @@ func NewPodSource( _, _ = podInformer.Informer().AddEventHandler(informers.DefaultEventHandler()) - // Transformer is used to reduce the memory usage of the informer. - // The pod informer will otherwise store a full in-memory, go-typed copy of all pod schemas in the cluster. - // If watchList is not used it will not prevent memory bursts on the initial informer sync. - podInformer.Informer().SetTransform(func(i interface{}) (interface{}, error) { - pod, ok := i.(*corev1.Pod) - if !ok { - return nil, fmt.Errorf("object is not a pod") - } - if pod.UID == "" { - // Pod was already transformed and we must be idempotent. - return pod, nil - } - return &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - // Name/namespace must always be kept for the informer to work. - Name: pod.Name, - Namespace: pod.Namespace, - // Used by the controller. This includes non-external-dns prefixed annotations. - Annotations: pod.Annotations, - }, - Spec: corev1.PodSpec{ - HostNetwork: pod.Spec.HostNetwork, - NodeName: pod.Spec.NodeName, - }, - Status: corev1.PodStatus{ - PodIP: pod.Status.PodIP, - }, - }, nil - }) + if fqdnTemplate == "" { + // Transformer is used to reduce the memory usage of the informer. + // The pod informer will otherwise store a full in-memory, go-typed copy of all pod schemas in the cluster. + // If watchList is not used it will not prevent memory bursts on the initial informer sync. + // When fqdnTemplate is used the entire pod needs to be provided to the rendering call, but the informer itself becomes unneeded. + podInformer.Informer().SetTransform(func(i interface{}) (interface{}, error) { + pod, ok := i.(*corev1.Pod) + if !ok { + return nil, fmt.Errorf("object is not a pod") + } + if pod.UID == "" { + // Pod was already transformed and we must be idempotent. + return pod, nil + } + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + // Name/namespace must always be kept for the informer to work. + Name: pod.Name, + Namespace: pod.Namespace, + // Used by the controller. This includes non-external-dns prefixed annotations. + Annotations: pod.Annotations, + }, + Spec: corev1.PodSpec{ + HostNetwork: pod.Spec.HostNetwork, + NodeName: pod.Spec.NodeName, + }, + Status: corev1.PodStatus{ + PodIP: pod.Status.PodIP, + }, + }, nil + }) + } + _, _ = nodeInformer.Informer().AddEventHandler(informers.DefaultEventHandler()) informerFactory.Start(ctx.Done()) diff --git a/source/pod_test.go b/source/pod_test.go index d95471660..e9392bcf4 100644 --- a/source/pod_test.go +++ b/source/pod_test.go @@ -1000,82 +1000,145 @@ func nodesFixturesIPv4() []*corev1.Node { } func TestPodTransformerInPodSource(t *testing.T) { - ctx := t.Context() - fakeClient := fake.NewClientset() + t.Run("transformer set", func(t *testing.T) { + ctx := t.Context() + fakeClient := fake.NewClientset() - pod := &v1.Pod{ - Spec: v1.PodSpec{ - Containers: []v1.Container{{ - Name: "test", - }}, - Hostname: "test-hostname", - NodeName: "test-node", - HostNetwork: true, - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: "test-ns", - Name: "test-name", - Labels: map[string]string{ - "label1": "value1", - "label2": "value2", - "label3": "value3", + pod := &v1.Pod{ + Spec: v1.PodSpec{ + Containers: []v1.Container{{ + Name: "test", + }}, + Hostname: "test-hostname", + NodeName: "test-node", + HostNetwork: true, }, - Annotations: map[string]string{ - "user-annotation": "value", - "external-dns.alpha.kubernetes.io/hostname": "test-hostname", - "external-dns.alpha.kubernetes.io/random": "value", - "other/annotation": "value", + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test-ns", + Name: "test-name", + Labels: map[string]string{ + "label1": "value1", + "label2": "value2", + "label3": "value3", + }, + Annotations: map[string]string{ + "user-annotation": "value", + "external-dns.alpha.kubernetes.io/hostname": "test-hostname", + "external-dns.alpha.kubernetes.io/random": "value", + "other/annotation": "value", + }, + UID: "someuid", }, - UID: "someuid", - }, - Status: v1.PodStatus{ - PodIP: "127.0.0.1", - HostIP: "127.0.0.2", - Conditions: []v1.PodCondition{{ - Type: v1.PodReady, - Status: v1.ConditionTrue, - }, { - Type: v1.ContainersReady, - Status: v1.ConditionFalse, - }}, - }, - } + Status: v1.PodStatus{ + PodIP: "127.0.0.1", + HostIP: "127.0.0.2", + Conditions: []v1.PodCondition{{ + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, { + Type: v1.ContainersReady, + Status: v1.ConditionFalse, + }}, + }, + } - _, err := fakeClient.CoreV1().Pods(pod.Namespace).Create(context.Background(), pod, metav1.CreateOptions{}) - require.NoError(t, err) + _, err := fakeClient.CoreV1().Pods(pod.Namespace).Create(context.Background(), pod, metav1.CreateOptions{}) + require.NoError(t, err) - // Should not error when creating the source - src, err := NewPodSource(ctx, fakeClient, "", "", false, "", "", false, "", nil) - require.NoError(t, err) - ps, ok := src.(*podSource) - require.True(t, ok) + // Should not error when creating the source + src, err := NewPodSource(ctx, fakeClient, "", "", false, "", "", false, "", nil) + require.NoError(t, err) + ps, ok := src.(*podSource) + require.True(t, ok) - retrieved, err := ps.podInformer.Lister().Pods("test-ns").Get("test-name") - require.NoError(t, err) + retrieved, err := ps.podInformer.Lister().Pods("test-ns").Get("test-name") + require.NoError(t, err) - // Metadata - assert.Equal(t, "test-name", retrieved.Name) - assert.Equal(t, "test-ns", retrieved.Namespace) - assert.Empty(t, retrieved.UID) - assert.Empty(t, retrieved.Labels) - // Filtered - assert.Equal(t, map[string]string{ - "user-annotation": "value", - "external-dns.alpha.kubernetes.io/hostname": "test-hostname", - "external-dns.alpha.kubernetes.io/random": "value", - "other/annotation": "value", - }, retrieved.Annotations) + // Metadata + assert.Equal(t, "test-name", retrieved.Name) + assert.Equal(t, "test-ns", retrieved.Namespace) + assert.Empty(t, retrieved.UID) + assert.Empty(t, retrieved.Labels) + // Filtered + assert.Equal(t, map[string]string{ + "user-annotation": "value", + "external-dns.alpha.kubernetes.io/hostname": "test-hostname", + "external-dns.alpha.kubernetes.io/random": "value", + "other/annotation": "value", + }, retrieved.Annotations) - // Spec - assert.Empty(t, retrieved.Spec.Containers) - assert.Empty(t, retrieved.Spec.Hostname) - assert.Equal(t, "test-node", retrieved.Spec.NodeName) - assert.True(t, retrieved.Spec.HostNetwork) + // Spec + assert.Empty(t, retrieved.Spec.Containers) + assert.Empty(t, retrieved.Spec.Hostname) + assert.Equal(t, "test-node", retrieved.Spec.NodeName) + assert.True(t, retrieved.Spec.HostNetwork) - // Status - assert.Empty(t, retrieved.Status.ContainerStatuses) - assert.Empty(t, retrieved.Status.InitContainerStatuses) - assert.Empty(t, retrieved.Status.HostIP) - assert.Equal(t, "127.0.0.1", retrieved.Status.PodIP) - assert.Empty(t, retrieved.Status.Conditions) + // Status + assert.Empty(t, retrieved.Status.ContainerStatuses) + assert.Empty(t, retrieved.Status.InitContainerStatuses) + assert.Empty(t, retrieved.Status.HostIP) + assert.Equal(t, "127.0.0.1", retrieved.Status.PodIP) + assert.Empty(t, retrieved.Status.Conditions) + }) + + t.Run("transormer is not used when fqdnTemplate is set", func(t *testing.T) { + ctx := t.Context() + fakeClient := fake.NewClientset() + + pod := &v1.Pod{ + Spec: v1.PodSpec{ + Containers: []v1.Container{{ + Name: "test", + }}, + Hostname: "test-hostname", + NodeName: "test-node", + HostNetwork: true, + }, + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test-ns", + Name: "test-name", + Labels: map[string]string{ + "label1": "value1", + "label2": "value2", + "label3": "value3", + }, + Annotations: map[string]string{ + "user-annotation": "value", + "external-dns.alpha.kubernetes.io/hostname": "test-hostname", + "external-dns.alpha.kubernetes.io/random": "value", + "other/annotation": "value", + }, + UID: "someuid", + }, + Status: v1.PodStatus{ + PodIP: "127.0.0.1", + HostIP: "127.0.0.2", + Conditions: []v1.PodCondition{{ + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, { + Type: v1.ContainersReady, + Status: v1.ConditionFalse, + }}, + }, + } + + _, err := fakeClient.CoreV1().Pods(pod.Namespace).Create(context.Background(), pod, metav1.CreateOptions{}) + require.NoError(t, err) + + // Should not error when creating the source + src, err := NewPodSource(ctx, fakeClient, "", "", false, "", "template", false, "", nil) + require.NoError(t, err) + ps, ok := src.(*podSource) + require.True(t, ok) + + retrieved, err := ps.podInformer.Lister().Pods("test-ns").Get("test-name") + require.NoError(t, err) + + // Metadata + assert.Equal(t, "test-name", retrieved.Name) + assert.Equal(t, "test-ns", retrieved.Namespace) + assert.NotEmpty(t, retrieved.UID) + assert.NotEmpty(t, retrieved.Labels) + }) }