Do not use transformer when fqdnTemplate is set

This commit is contained in:
Valerian Roche 2025-07-07 21:30:53 -04:00
parent 59d54158ee
commit 2ed7bb3d7a
No known key found for this signature in database
GPG Key ID: DBDC687C250F4CD2
2 changed files with 165 additions and 98 deletions

View File

@ -78,35 +78,39 @@ func NewPodSource(
_, _ = podInformer.Informer().AddEventHandler(informers.DefaultEventHandler()) _, _ = podInformer.Informer().AddEventHandler(informers.DefaultEventHandler())
// Transformer is used to reduce the memory usage of the informer. if fqdnTemplate == "" {
// The pod informer will otherwise store a full in-memory, go-typed copy of all pod schemas in the cluster. // Transformer is used to reduce the memory usage of the informer.
// If watchList is not used it will not prevent memory bursts on the initial informer sync. // The pod informer will otherwise store a full in-memory, go-typed copy of all pod schemas in the cluster.
podInformer.Informer().SetTransform(func(i interface{}) (interface{}, error) { // If watchList is not used it will not prevent memory bursts on the initial informer sync.
pod, ok := i.(*corev1.Pod) // When fqdnTemplate is used the entire pod needs to be provided to the rendering call, but the informer itself becomes unneeded.
if !ok { podInformer.Informer().SetTransform(func(i interface{}) (interface{}, error) {
return nil, fmt.Errorf("object is not a pod") pod, ok := i.(*corev1.Pod)
} if !ok {
if pod.UID == "" { return nil, fmt.Errorf("object is not a pod")
// Pod was already transformed and we must be idempotent. }
return pod, nil if pod.UID == "" {
} // Pod was already transformed and we must be idempotent.
return &corev1.Pod{ return pod, nil
ObjectMeta: metav1.ObjectMeta{ }
// Name/namespace must always be kept for the informer to work. return &corev1.Pod{
Name: pod.Name, ObjectMeta: metav1.ObjectMeta{
Namespace: pod.Namespace, // Name/namespace must always be kept for the informer to work.
// Used by the controller. This includes non-external-dns prefixed annotations. Name: pod.Name,
Annotations: pod.Annotations, Namespace: pod.Namespace,
}, // Used by the controller. This includes non-external-dns prefixed annotations.
Spec: corev1.PodSpec{ Annotations: pod.Annotations,
HostNetwork: pod.Spec.HostNetwork, },
NodeName: pod.Spec.NodeName, Spec: corev1.PodSpec{
}, HostNetwork: pod.Spec.HostNetwork,
Status: corev1.PodStatus{ NodeName: pod.Spec.NodeName,
PodIP: pod.Status.PodIP, },
}, Status: corev1.PodStatus{
}, nil PodIP: pod.Status.PodIP,
}) },
}, nil
})
}
_, _ = nodeInformer.Informer().AddEventHandler(informers.DefaultEventHandler()) _, _ = nodeInformer.Informer().AddEventHandler(informers.DefaultEventHandler())
informerFactory.Start(ctx.Done()) informerFactory.Start(ctx.Done())

View File

@ -1000,82 +1000,145 @@ func nodesFixturesIPv4() []*corev1.Node {
} }
func TestPodTransformerInPodSource(t *testing.T) { func TestPodTransformerInPodSource(t *testing.T) {
ctx := t.Context() t.Run("transformer set", func(t *testing.T) {
fakeClient := fake.NewClientset() ctx := t.Context()
fakeClient := fake.NewClientset()
pod := &v1.Pod{ pod := &v1.Pod{
Spec: v1.PodSpec{ Spec: v1.PodSpec{
Containers: []v1.Container{{ Containers: []v1.Container{{
Name: "test", Name: "test",
}}, }},
Hostname: "test-hostname", Hostname: "test-hostname",
NodeName: "test-node", NodeName: "test-node",
HostNetwork: true, 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{ ObjectMeta: metav1.ObjectMeta{
"user-annotation": "value", Namespace: "test-ns",
"external-dns.alpha.kubernetes.io/hostname": "test-hostname", Name: "test-name",
"external-dns.alpha.kubernetes.io/random": "value", Labels: map[string]string{
"other/annotation": "value", "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",
Status: v1.PodStatus{ HostIP: "127.0.0.2",
PodIP: "127.0.0.1", Conditions: []v1.PodCondition{{
HostIP: "127.0.0.2", Type: v1.PodReady,
Conditions: []v1.PodCondition{{ Status: v1.ConditionTrue,
Type: v1.PodReady, }, {
Status: v1.ConditionTrue, Type: v1.ContainersReady,
}, { Status: v1.ConditionFalse,
Type: v1.ContainersReady, }},
Status: v1.ConditionFalse, },
}}, }
},
}
_, err := fakeClient.CoreV1().Pods(pod.Namespace).Create(context.Background(), pod, metav1.CreateOptions{}) _, err := fakeClient.CoreV1().Pods(pod.Namespace).Create(context.Background(), pod, metav1.CreateOptions{})
require.NoError(t, err) require.NoError(t, err)
// Should not error when creating the source // Should not error when creating the source
src, err := NewPodSource(ctx, fakeClient, "", "", false, "", "", false, "", nil) src, err := NewPodSource(ctx, fakeClient, "", "", false, "", "", false, "", nil)
require.NoError(t, err) require.NoError(t, err)
ps, ok := src.(*podSource) ps, ok := src.(*podSource)
require.True(t, ok) require.True(t, ok)
retrieved, err := ps.podInformer.Lister().Pods("test-ns").Get("test-name") retrieved, err := ps.podInformer.Lister().Pods("test-ns").Get("test-name")
require.NoError(t, err) require.NoError(t, err)
// Metadata // Metadata
assert.Equal(t, "test-name", retrieved.Name) assert.Equal(t, "test-name", retrieved.Name)
assert.Equal(t, "test-ns", retrieved.Namespace) assert.Equal(t, "test-ns", retrieved.Namespace)
assert.Empty(t, retrieved.UID) assert.Empty(t, retrieved.UID)
assert.Empty(t, retrieved.Labels) assert.Empty(t, retrieved.Labels)
// Filtered // Filtered
assert.Equal(t, map[string]string{ assert.Equal(t, map[string]string{
"user-annotation": "value", "user-annotation": "value",
"external-dns.alpha.kubernetes.io/hostname": "test-hostname", "external-dns.alpha.kubernetes.io/hostname": "test-hostname",
"external-dns.alpha.kubernetes.io/random": "value", "external-dns.alpha.kubernetes.io/random": "value",
"other/annotation": "value", "other/annotation": "value",
}, retrieved.Annotations) }, retrieved.Annotations)
// Spec // Spec
assert.Empty(t, retrieved.Spec.Containers) assert.Empty(t, retrieved.Spec.Containers)
assert.Empty(t, retrieved.Spec.Hostname) assert.Empty(t, retrieved.Spec.Hostname)
assert.Equal(t, "test-node", retrieved.Spec.NodeName) assert.Equal(t, "test-node", retrieved.Spec.NodeName)
assert.True(t, retrieved.Spec.HostNetwork) assert.True(t, retrieved.Spec.HostNetwork)
// Status // Status
assert.Empty(t, retrieved.Status.ContainerStatuses) assert.Empty(t, retrieved.Status.ContainerStatuses)
assert.Empty(t, retrieved.Status.InitContainerStatuses) assert.Empty(t, retrieved.Status.InitContainerStatuses)
assert.Empty(t, retrieved.Status.HostIP) assert.Empty(t, retrieved.Status.HostIP)
assert.Equal(t, "127.0.0.1", retrieved.Status.PodIP) assert.Equal(t, "127.0.0.1", retrieved.Status.PodIP)
assert.Empty(t, retrieved.Status.Conditions) 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)
})
} }