Skip to content

Commit

Permalink
feat: allow pod IPs even for non-hostNetwork pods
Browse files Browse the repository at this point in the history
but only for the internalHostnameAnnotationKey which doesn't use the node's IP anyway
tests validate this for annotations with:
- mixing pods in the host network with others that are not
- multiple comma separated annotations per Pod
- explicitly set targets
- IPv4 and IPv6
  • Loading branch information
peterhoneder authored and raoulbhatia committed Sep 27, 2024
1 parent 0928d52 commit f1424a2
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 42 deletions.
70 changes: 34 additions & 36 deletions source/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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)
}
}
}
}
Expand Down
90 changes: 84 additions & 6 deletions source/pod_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
},
},
},
{
Expand All @@ -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{
Expand Down Expand Up @@ -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",
},
},
},
},
{
Expand Down Expand Up @@ -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",
},
},
},
},
{
Expand All @@ -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{
Expand Down Expand Up @@ -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",
},
},
},
},
{
Expand Down Expand Up @@ -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{
Expand All @@ -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",
},
},
Expand All @@ -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",
},
},
Expand Down

0 comments on commit f1424a2

Please sign in to comment.