mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2026-05-05 06:36:11 +02:00
test(source/service): add serviceTypeFilter edge case (#5872)
* chore(source/service): serviceTypeFilter edge case tests Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> * chore(source/service): serviceTypeFilter edge case tests Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com> --------- Signed-off-by: ivan katliarchuk <ivan.katliarchuk@gmail.com>
This commit is contained in:
parent
1da86e8cfb
commit
1f9edcb7fc
@ -87,7 +87,18 @@ type serviceSource struct {
|
||||
}
|
||||
|
||||
// NewServiceSource creates a new serviceSource with the given config.
|
||||
func NewServiceSource(ctx context.Context, kubeClient kubernetes.Interface, namespace, annotationFilter, fqdnTemplate string, combineFqdnAnnotation bool, compatibility string, publishInternal, publishHostIP, alwaysPublishNotReadyAddresses bool, serviceTypeFilter []string, ignoreHostnameAnnotation bool, labelSelector labels.Selector, resolveLoadBalancerHostname, listenEndpointEvents bool, exposeInternalIPv6 bool) (Source, error) {
|
||||
func NewServiceSource(
|
||||
ctx context.Context,
|
||||
kubeClient kubernetes.Interface,
|
||||
namespace, annotationFilter, fqdnTemplate string,
|
||||
combineFqdnAnnotation bool, compatibility string,
|
||||
publishInternal, publishHostIP, alwaysPublishNotReadyAddresses bool,
|
||||
serviceTypeFilter []string,
|
||||
ignoreHostnameAnnotation bool,
|
||||
labelSelector labels.Selector,
|
||||
resolveLoadBalancerHostname,
|
||||
listenEndpointEvents, exposeInternalIPv6 bool,
|
||||
) (Source, error) {
|
||||
tmpl, err := fqdn.ParseTemplate(fqdnTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -139,7 +150,7 @@ func NewServiceSource(ctx context.Context, kubeClient kubernetes.Interface, name
|
||||
// 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) {
|
||||
_ = podInformer.Informer().SetTransform(func(i interface{}) (interface{}, error) {
|
||||
pod, ok := i.(*v1.Pod)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("object is not a pod")
|
||||
@ -349,6 +360,7 @@ func (sc *serviceSource) extractHeadlessEndpoints(svc *v1.Service, hostname stri
|
||||
targetsByHeadlessDomainAndType := sc.processHeadlessEndpointsFromSlices(
|
||||
svc, pods, endpointSlices, hostname, endpointsType, publishPodIPs, publishNotReadyAddresses)
|
||||
endpoints = buildHeadlessEndpoints(svc, targetsByHeadlessDomainAndType, ttl)
|
||||
|
||||
return endpoints
|
||||
}
|
||||
|
||||
@ -436,7 +448,11 @@ func findPodForEndpoint(ep discoveryv1.Endpoint, pods []*v1.Pod) *v1.Pod {
|
||||
}
|
||||
|
||||
// Helper to get targets for domain
|
||||
func (sc *serviceSource) getTargetsForDomain(pod *v1.Pod, ep discoveryv1.Endpoint, endpointSlice *discoveryv1.EndpointSlice, endpointsType string, headlessDomain string) endpoint.Targets {
|
||||
func (sc *serviceSource) getTargetsForDomain(
|
||||
pod *v1.Pod,
|
||||
ep discoveryv1.Endpoint,
|
||||
endpointSlice *discoveryv1.EndpointSlice,
|
||||
endpointsType, headlessDomain string) endpoint.Targets {
|
||||
targets := annotations.TargetsFromTargetAnnotation(pod.Annotations)
|
||||
if len(targets) == 0 {
|
||||
if endpointsType == EndpointsTypeNodeExternalIP {
|
||||
|
||||
@ -31,13 +31,14 @@ import (
|
||||
func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
|
||||
|
||||
for _, tt := range []struct {
|
||||
title string
|
||||
services []*v1.Service
|
||||
endpointSlices []*discoveryv1.EndpointSlice
|
||||
fqdnTemplate string
|
||||
combineFQDN bool
|
||||
publishHostIp bool
|
||||
expected []*endpoint.Endpoint
|
||||
title string
|
||||
services []*v1.Service
|
||||
endpointSlices []*discoveryv1.EndpointSlice
|
||||
fqdnTemplate string
|
||||
combineFQDN bool
|
||||
publishHostIp bool
|
||||
serviceTypesFilter []string
|
||||
expected []*endpoint.Endpoint
|
||||
}{
|
||||
{
|
||||
title: "templating with multiple services",
|
||||
@ -182,6 +183,129 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
|
||||
{DNSName: "www.service-two.website.example.tld", RecordType: endpoint.RecordTypeCNAME, Targets: endpoint.Targets{"www.bucket-name.amazonaws.com"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "fqdn with endpoint-type annotation and loose service type filtering",
|
||||
serviceTypesFilter: []string{},
|
||||
services: []*v1.Service{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "svc-ns",
|
||||
Name: "svc-one",
|
||||
Annotations: map[string]string{
|
||||
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
|
||||
},
|
||||
},
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeClusterIP,
|
||||
ClusterIP: v1.ClusterIPNone,
|
||||
ClusterIPs: []string{v1.ClusterIPNone},
|
||||
},
|
||||
Status: v1.ServiceStatus{
|
||||
LoadBalancer: v1.LoadBalancerStatus{},
|
||||
},
|
||||
},
|
||||
},
|
||||
endpointSlices: []*discoveryv1.EndpointSlice{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc-one-xxxxx",
|
||||
Namespace: "svc-ns",
|
||||
Labels: map[string]string{
|
||||
discoveryv1.LabelServiceName: "svc-one",
|
||||
v1.IsHeadlessService: "",
|
||||
},
|
||||
},
|
||||
AddressType: discoveryv1.AddressTypeIPv4,
|
||||
Endpoints: []discoveryv1.Endpoint{
|
||||
{
|
||||
Addresses: []string{"100.66.2.246"},
|
||||
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
|
||||
NodeName: testutils.ToPtr("test-node"),
|
||||
TargetRef: &v1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Name: "pod-1",
|
||||
Namespace: "svc-ns",
|
||||
},
|
||||
},
|
||||
{
|
||||
Addresses: []string{"100.66.2.247"},
|
||||
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
|
||||
NodeName: testutils.ToPtr("test-node"),
|
||||
TargetRef: &v1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Name: "pod-2",
|
||||
Namespace: "svc-ns",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fqdnTemplate: "{{.Name}}.{{.Namespace}}.cluster.com",
|
||||
expected: []*endpoint.Endpoint{
|
||||
{DNSName: "ip-10-1-164-158.internal.svc-one.svc-ns.cluster.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"203.0.113.10"}},
|
||||
{DNSName: "svc-one.svc-ns.cluster.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"203.0.113.10"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "fqdn with endpoint-type annotation and service type filtering does not include required type",
|
||||
serviceTypesFilter: []string{string(v1.ServiceTypeClusterIP)},
|
||||
services: []*v1.Service{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "svc-ns",
|
||||
Name: "svc-one",
|
||||
Annotations: map[string]string{
|
||||
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
|
||||
},
|
||||
},
|
||||
Spec: v1.ServiceSpec{
|
||||
Type: v1.ServiceTypeClusterIP,
|
||||
ClusterIP: v1.ClusterIPNone,
|
||||
ClusterIPs: []string{v1.ClusterIPNone},
|
||||
},
|
||||
Status: v1.ServiceStatus{
|
||||
LoadBalancer: v1.LoadBalancerStatus{},
|
||||
},
|
||||
},
|
||||
},
|
||||
endpointSlices: []*discoveryv1.EndpointSlice{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "svc-one-xxxxx",
|
||||
Namespace: "svc-ns",
|
||||
Labels: map[string]string{
|
||||
discoveryv1.LabelServiceName: "svc-one",
|
||||
v1.IsHeadlessService: "",
|
||||
},
|
||||
},
|
||||
AddressType: discoveryv1.AddressTypeIPv4,
|
||||
Endpoints: []discoveryv1.Endpoint{
|
||||
{
|
||||
Addresses: []string{"100.66.2.246"},
|
||||
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
|
||||
NodeName: testutils.ToPtr("test-node"),
|
||||
TargetRef: &v1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Name: "pod-1",
|
||||
Namespace: "svc-ns",
|
||||
},
|
||||
},
|
||||
{
|
||||
Addresses: []string{"100.66.2.247"},
|
||||
Hostname: testutils.ToPtr("ip-10-1-164-158.internal"),
|
||||
NodeName: testutils.ToPtr("test-node"),
|
||||
TargetRef: &v1.ObjectReference{
|
||||
Kind: "Pod",
|
||||
Name: "pod-2",
|
||||
Namespace: "svc-ns",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
fqdnTemplate: "{{.Name}}.{{.Namespace}}.cluster.com",
|
||||
expected: []*endpoint.Endpoint{},
|
||||
},
|
||||
{
|
||||
title: "templating resolve service with zone PreferSameTrafficDistribution and topology.kubernetes.io/zone annotation",
|
||||
services: []*v1.Service{
|
||||
@ -571,6 +695,17 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
_, err := kubeClient.CoreV1().Nodes().Create(t.Context(), &v1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test-node"},
|
||||
Status: v1.NodeStatus{
|
||||
Addresses: []v1.NodeAddress{
|
||||
{Type: v1.NodeExternalIP, Address: "203.0.113.10"},
|
||||
{Type: v1.NodeInternalIP, Address: "10.0.0.10"},
|
||||
},
|
||||
},
|
||||
}, metav1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create endpoints and pods for the services
|
||||
for _, el := range tt.endpointSlices {
|
||||
_, err := kubeClient.DiscoveryV1().EndpointSlices(el.Namespace).Create(t.Context(), el, metav1.CreateOptions{})
|
||||
@ -583,6 +718,7 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Hostname: *ep.Hostname,
|
||||
NodeName: "test-node",
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
HostIP: fmt.Sprintf("10.1.20.4%d", i),
|
||||
@ -603,7 +739,7 @@ func TestServiceSourceFqdnTemplatingExamples(t *testing.T) {
|
||||
true,
|
||||
tt.publishHostIp,
|
||||
true,
|
||||
[]string{},
|
||||
tt.serviceTypesFilter,
|
||||
false,
|
||||
labels.Everything(),
|
||||
false,
|
||||
|
||||
@ -3171,6 +3171,102 @@ func TestHeadlessServices(t *testing.T) {
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"headless service with endpoints-type annotation is outside of serviceTypeFilter scope",
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
v1.ServiceTypeClusterIP,
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
false,
|
||||
map[string]string{"component": "foo"},
|
||||
map[string]string{
|
||||
annotations.HostnameKey: "service.example.org",
|
||||
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
|
||||
},
|
||||
map[string]string{},
|
||||
v1.ClusterIPNone,
|
||||
[]string{"2001:db8::1"},
|
||||
[]string{"2001:db8::4"},
|
||||
map[string]string{
|
||||
"component": "foo",
|
||||
},
|
||||
[]string{},
|
||||
[]string{"foo"},
|
||||
[]string{"", "", ""},
|
||||
[]bool{true, true, true},
|
||||
false,
|
||||
[]v1.Node{
|
||||
{
|
||||
Status: v1.NodeStatus{
|
||||
Addresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeExternalIP,
|
||||
Address: "1.2.3.4",
|
||||
},
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: "10.0.10.12",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{string(v1.ServiceTypeClusterIP)},
|
||||
[]*endpoint.Endpoint{},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"headless service with endpoints-type annotation is in the scope of serviceTypeFilter",
|
||||
"",
|
||||
"testing",
|
||||
"foo",
|
||||
v1.ServiceTypeClusterIP,
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
false,
|
||||
map[string]string{"component": "foo"},
|
||||
map[string]string{
|
||||
annotations.HostnameKey: "service.example.org",
|
||||
annotations.EndpointsTypeKey: EndpointsTypeNodeExternalIP,
|
||||
},
|
||||
map[string]string{},
|
||||
v1.ClusterIPNone,
|
||||
[]string{"2001:db8::1"},
|
||||
[]string{"1.2.3.4"},
|
||||
map[string]string{
|
||||
"component": "foo",
|
||||
},
|
||||
[]string{},
|
||||
[]string{"foo"},
|
||||
[]string{"", "", ""},
|
||||
[]bool{true, true, true},
|
||||
false,
|
||||
[]v1.Node{
|
||||
{
|
||||
Status: v1.NodeStatus{
|
||||
Addresses: []v1.NodeAddress{
|
||||
{
|
||||
Type: v1.NodeExternalIP,
|
||||
Address: "1.2.3.4",
|
||||
},
|
||||
{
|
||||
Type: v1.NodeInternalIP,
|
||||
Address: "10.0.10.12",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
[]string{string(v1.ServiceTypeClusterIP), string(v1.ServiceTypeNodePort)},
|
||||
[]*endpoint.Endpoint{
|
||||
{DNSName: "service.example.org", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"1.2.3.4"}},
|
||||
},
|
||||
false,
|
||||
},
|
||||
} {
|
||||
|
||||
t.Run(tc.title, func(t *testing.T) {
|
||||
@ -3198,7 +3294,7 @@ func TestHeadlessServices(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
var endpointSliceEndpoints []discoveryv1.Endpoint
|
||||
for i, podname := range tc.podnames {
|
||||
for i, podName := range tc.podnames {
|
||||
pod := &v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{},
|
||||
@ -3206,7 +3302,7 @@ func TestHeadlessServices(t *testing.T) {
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: tc.svcNamespace,
|
||||
Name: podname,
|
||||
Name: podName,
|
||||
Labels: tc.labels,
|
||||
Annotations: tc.podAnnotations,
|
||||
},
|
||||
@ -3224,7 +3320,7 @@ func TestHeadlessServices(t *testing.T) {
|
||||
TargetRef: &v1.ObjectReference{
|
||||
APIVersion: "",
|
||||
Kind: "Pod",
|
||||
Name: podname,
|
||||
Name: podName,
|
||||
},
|
||||
Conditions: discoveryv1.EndpointConditions{
|
||||
Ready: &tc.podsReady[i],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user