diff --git a/source/pod.go b/source/pod.go index 4a5ea4c3bf..3946d400a3 100644 --- a/source/pod.go +++ b/source/pod.go @@ -21,7 +21,6 @@ import ( "sigs.k8s.io/external-dns/endpoint" - log "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" kubeinformers "k8s.io/client-go/informers" @@ -84,13 +83,9 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error endpointMap := make(map[endpoint.EndpointKey][]string) for _, pod := range pods { - if !pod.Spec.HostNetwork { - log.Debugf("skipping pod %s. hostNetwork=false", pod.Name) - continue - } - targets := getTargetsFromTargetAnnotation(pod.Annotations) + // accept hostname annotations that point to the pod's IP, no matter if the pod spec uses the host network if domainAnnotation, ok := pod.Annotations[internalHostnameAnnotationKey]; ok { domainList := splitHostnameAnnotation(domainAnnotation) for _, domain := range domainList { @@ -104,43 +99,46 @@ func (ps *podSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error } } - if domainAnnotation, ok := pod.Annotations[hostnameAnnotationKey]; ok { - domainList := splitHostnameAnnotation(domainAnnotation) - for _, domain := range domainList { - if len(targets) == 0 { - node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName) - for _, address := range node.Status.Addresses { - recordType := suitableType(address.Address) - // IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well. - if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) { - addToEndpointMap(endpointMap, domain, recordType, address.Address) + // accept annotations that point to the node's external IP (or IPv6 NodeInternalIP) only for pods using the host network + if pod.Spec.HostNetwork { + if domainAnnotation, ok := pod.Annotations[hostnameAnnotationKey]; ok { + domainList := splitHostnameAnnotation(domainAnnotation) + for _, domain := range domainList { + if len(targets) == 0 { + node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName) + for _, address := range node.Status.Addresses { + recordType := suitableType(address.Address) + // IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well. + if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) { + addToEndpointMap(endpointMap, domain, recordType, address.Address) + } + } + } else { + for _, target := range targets { + addToEndpointMap(endpointMap, domain, suitableType(target), target) } - } - } else { - for _, target := range targets { - addToEndpointMap(endpointMap, domain, suitableType(target), target) } } } - } - if ps.compatibility == "kops-dns-controller" { - if domainAnnotation, ok := pod.Annotations[kopsDNSControllerInternalHostnameAnnotationKey]; ok { - domainList := splitHostnameAnnotation(domainAnnotation) - for _, domain := range domainList { - addToEndpointMap(endpointMap, domain, suitableType(pod.Status.PodIP), pod.Status.PodIP) + if ps.compatibility == "kops-dns-controller" { + if domainAnnotation, ok := pod.Annotations[kopsDNSControllerInternalHostnameAnnotationKey]; ok { + domainList := splitHostnameAnnotation(domainAnnotation) + for _, domain := range domainList { + addToEndpointMap(endpointMap, domain, suitableType(pod.Status.PodIP), pod.Status.PodIP) + } } - } - if domainAnnotation, ok := pod.Annotations[kopsDNSControllerHostnameAnnotationKey]; ok { - domainList := splitHostnameAnnotation(domainAnnotation) - for _, domain := range domainList { - node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName) - for _, address := range node.Status.Addresses { - recordType := suitableType(address.Address) - // IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well. - if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) { - addToEndpointMap(endpointMap, domain, recordType, address.Address) + if domainAnnotation, ok := pod.Annotations[kopsDNSControllerHostnameAnnotationKey]; ok { + domainList := splitHostnameAnnotation(domainAnnotation) + for _, domain := range domainList { + node, _ := ps.nodeInformer.Lister().Get(pod.Spec.NodeName) + for _, address := range node.Status.Addresses { + recordType := suitableType(address.Address) + // IPv6 addresses are labeled as NodeInternalIP despite being usable externally as well. + if address.Type == corev1.NodeExternalIP || (address.Type == corev1.NodeInternalIP && recordType == endpoint.RecordTypeAAAA) { + addToEndpointMap(endpointMap, domain, recordType, address.Address) + } } } } diff --git a/source/pod_test.go b/source/pod_test.go index 24ce65d018..fa727c0483 100644 --- a/source/pod_test.go +++ b/source/pod_test.go @@ -178,6 +178,24 @@ func TestPodSource(t *testing.T) { PodIP: "10.0.1.2", }, }, + // this pod must be ignored because it's not in the host network and kops requires this + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod3", + Namespace: "kube-system", + Annotations: map[string]string{ + kopsDNSControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", + kopsDNSControllerHostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: false, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.3", + }, + }, }, }, { @@ -186,7 +204,7 @@ func TestPodSource(t *testing.T) { "", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2"}, RecordType: endpoint.RecordTypeAAAA}, - {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2"}, RecordType: endpoint.RecordTypeAAAA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"2001:DB8::1", "2001:DB8::2", "2001:DB8::3"}, RecordType: endpoint.RecordTypeAAAA}, }, false, []*corev1.Node{ @@ -246,6 +264,24 @@ func TestPodSource(t *testing.T) { PodIP: "2001:DB8::2", }, }, + // this pod's internal hostname annotation must not be ignored even though it's not in the host network + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod3", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: false, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "2001:DB8::3", + }, + }, }, }, { @@ -314,6 +350,24 @@ func TestPodSource(t *testing.T) { PodIP: "2001:DB8::2", }, }, + // this pod must be ignored because it's not in the host network and kops requires this (no matter the type of hostname annotation) + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod3", + Namespace: "kube-system", + Annotations: map[string]string{ + kopsDNSControllerInternalHostnameAnnotationKey: "internal.a.foo.example.org", + kopsDNSControllerHostnameAnnotationKey: "a.foo.example.org", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: false, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "2001:DB8::3", + }, + }, }, }, { @@ -322,7 +376,7 @@ func TestPodSource(t *testing.T) { "", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2"}, RecordType: endpoint.RecordTypeA}, - {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"208.1.2.1", "208.1.2.2", "208.1.2.3"}, RecordType: endpoint.RecordTypeA}, }, false, []*corev1.Node{ @@ -386,6 +440,25 @@ func TestPodSource(t *testing.T) { PodIP: "10.0.1.2", }, }, + // this pod's internal hostname annotation must not be ignored even though it's not in the host network (even when using a custom target annotation) + { + ObjectMeta: metav1.ObjectMeta{ + Name: "my-pod3", + Namespace: "kube-system", + Annotations: map[string]string{ + internalHostnameAnnotationKey: "internal.a.foo.example.org", + hostnameAnnotationKey: "a.foo.example.org", + targetAnnotationKey: "208.1.2.3", + }, + }, + Spec: corev1.PodSpec{ + HostNetwork: false, + NodeName: "my-node2", + }, + Status: corev1.PodStatus{ + PodIP: "10.0.1.3", + }, + }, }, }, { @@ -459,12 +532,16 @@ func TestPodSource(t *testing.T) { }, }, { - "pods with hostNetwore=false should be ignored", + "internal hostname annotations of pods with hostNetwore=false should still be added as valid records", "", "", []*endpoint.Endpoint{ {DNSName: "a.foo.example.org", Targets: endpoint.Targets{"54.10.11.1"}, RecordType: endpoint.RecordTypeA}, - {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, + {DNSName: "internal.a.foo.example.org", Targets: endpoint.Targets{"10.0.1.1", "100.0.1.2"}, RecordType: endpoint.RecordTypeA}, + // this annotation is part of a comma separated hostname list in the annotation + {DNSName: "internal.b.foo.example.org", Targets: endpoint.Targets{"10.0.1.1"}, RecordType: endpoint.RecordTypeA}, + // this annotation is part of a comma separated hostname list in the annotation + {DNSName: "internal.c.foo.example.org", Targets: endpoint.Targets{"100.0.1.2"}, RecordType: endpoint.RecordTypeA}, }, false, []*corev1.Node{ @@ -491,13 +568,14 @@ func TestPodSource(t *testing.T) { }, }, }, + // a mixed set of a host network pod and non host network pod should include both pod IPs of the internal hostname annotation in the endpoint []*corev1.Pod{ { ObjectMeta: metav1.ObjectMeta{ Name: "my-pod1", Namespace: "kube-system", Annotations: map[string]string{ - internalHostnameAnnotationKey: "internal.a.foo.example.org", + internalHostnameAnnotationKey: "internal.a.foo.example.org,internal.b.foo.example.org", hostnameAnnotationKey: "a.foo.example.org", }, }, @@ -514,7 +592,7 @@ func TestPodSource(t *testing.T) { Name: "my-pod2", Namespace: "kube-system", Annotations: map[string]string{ - internalHostnameAnnotationKey: "internal.a.foo.example.org", + internalHostnameAnnotationKey: "internal.a.foo.example.org,internal.c.foo.example.org", hostnameAnnotationKey: "a.foo.example.org", }, },