mirror of
https://github.com/kubernetes-sigs/external-dns.git
synced 2025-08-06 17:46:57 +02:00
* feat(source/node): Make exclusion of unschedulable Nodes configurable This fixes a behavioral regression introduced in #4761, where nodes that were previously added to DNS are removed when they are considered unschedulable, for example due to automated maintenance tasks. This change will introduce a new flag called `exclude-unschedulable`, which defaults to `true` in order to keep in line with the current behavior. However, it would also be reasonable to restore the initial behavior before * Allow testing for expected log entries in testNodeSourceEndpoints This commit adds the required logic to be able to test for the existence (and absence) of certain log messages in testNodeSourceEndpoints. As an example, this is implemented for the tests around excludeUnschedulable. A side effect of using LogsToBuffer is that tests can't run in parallel due to the log buffer being shared across all parallel test cases. As such, these specific tests are now executed one after another. * Ensure logging is only hooked for tests that require it * Document new exclude-unschedulable flag for nodes source
576 lines
20 KiB
Go
576 lines
20 KiB
Go
/*
|
|
Copyright 2019 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package source
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"testing"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"sigs.k8s.io/external-dns/internal/testutils"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
v1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/client-go/kubernetes/fake"
|
|
|
|
"sigs.k8s.io/external-dns/endpoint"
|
|
)
|
|
|
|
func TestNodeSource(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("NewNodeSource", testNodeSourceNewNodeSource)
|
|
t.Run("Endpoints", testNodeSourceEndpoints)
|
|
t.Run("EndpointsIPv6", testNodeEndpointsWithIPv6)
|
|
}
|
|
|
|
// testNodeSourceNewNodeSource tests that NewNodeService doesn't return an error.
|
|
func testNodeSourceNewNodeSource(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, ti := range []struct {
|
|
title string
|
|
annotationFilter string
|
|
fqdnTemplate string
|
|
expectError bool
|
|
}{
|
|
{
|
|
title: "invalid template",
|
|
expectError: true,
|
|
fqdnTemplate: "{{.Name",
|
|
},
|
|
{
|
|
title: "valid empty template",
|
|
expectError: false,
|
|
},
|
|
{
|
|
title: "valid template",
|
|
expectError: false,
|
|
fqdnTemplate: "{{.Name}}-{{.Namespace}}.ext-dns.test.com",
|
|
},
|
|
{
|
|
title: "non-empty annotation filter label",
|
|
expectError: false,
|
|
annotationFilter: "kubernetes.io/ingress.class=nginx",
|
|
},
|
|
} {
|
|
ti := ti
|
|
t.Run(ti.title, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := NewNodeSource(
|
|
context.TODO(),
|
|
fake.NewSimpleClientset(),
|
|
ti.annotationFilter,
|
|
ti.fqdnTemplate,
|
|
labels.Everything(),
|
|
true,
|
|
true,
|
|
)
|
|
|
|
if ti.expectError {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// testNodeSourceEndpoints tests that various node generate the correct endpoints.
|
|
func testNodeSourceEndpoints(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, tc := range []struct {
|
|
title string
|
|
annotationFilter string
|
|
labelSelector string
|
|
fqdnTemplate string
|
|
nodeName string
|
|
nodeAddresses []v1.NodeAddress
|
|
labels map[string]string
|
|
annotations map[string]string
|
|
excludeUnschedulable bool // default to false
|
|
exposeInternalIPv6 bool // default to true for this version. Change later when the next minor version is released.
|
|
unschedulable bool // default to false
|
|
expected []*endpoint.Endpoint
|
|
expectError bool
|
|
expectedLogs []string
|
|
expectedAbsentLogs []string
|
|
}{
|
|
{
|
|
title: "node with short hostname returns one endpoint",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with fqdn returns one endpoint",
|
|
nodeName: "node1.example.org",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1.example.org", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "ipv6 node with fqdn returns one endpoint",
|
|
nodeName: "node1.example.org",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeInternalIP, Address: "2001:DB8::8"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "AAAA", DNSName: "node1.example.org", Targets: endpoint.Targets{"2001:DB8::8"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with fqdn template returns endpoint with expanded hostname",
|
|
fqdnTemplate: "{{.Name}}.example.org",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1.example.org", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with fqdn and fqdn template returns one endpoint",
|
|
fqdnTemplate: "{{.Name}}.example.org",
|
|
nodeName: "node1.example.org",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1.example.org.example.org", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with fqdn template returns two endpoints with multiple IP addresses and expanded hostname",
|
|
fqdnTemplate: "{{.Name}}.example.org",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}, {Type: v1.NodeExternalIP, Address: "5.6.7.8"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1.example.org", Targets: endpoint.Targets{"1.2.3.4", "5.6.7.8"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with fqdn template returns two endpoints with dual-stack IP addresses and expanded hostname",
|
|
fqdnTemplate: "{{.Name}}.example.org",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}, {Type: v1.NodeInternalIP, Address: "2001:DB8::8"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1.example.org", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
{RecordType: "AAAA", DNSName: "node1.example.org", Targets: endpoint.Targets{"2001:DB8::8"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with both external and internal IP returns an endpoint with external IP",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}, {Type: v1.NodeInternalIP, Address: "2.3.4.5"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with both external, internal, and IPv6 IP returns endpoints with external IPs",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}, {Type: v1.NodeInternalIP, Address: "2.3.4.5"}, {Type: v1.NodeInternalIP, Address: "2001:DB8::8"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
{RecordType: "AAAA", DNSName: "node1", Targets: endpoint.Targets{"2001:DB8::8"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with only internal IP returns an endpoint with internal IP",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeInternalIP, Address: "2.3.4.5"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"2.3.4.5"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with only internal IPs returns endpoints with internal IPs",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeInternalIP, Address: "2.3.4.5"}, {Type: v1.NodeInternalIP, Address: "2001:DB8::8"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"2.3.4.5"}},
|
|
{RecordType: "AAAA", DNSName: "node1", Targets: endpoint.Targets{"2001:DB8::8"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with only internal IPs with expose internal IP as false shouldn't return AAAA endpoints with internal IPs",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: false,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeInternalIP, Address: "2.3.4.5"}, {Type: v1.NodeInternalIP, Address: "2001:DB8::9"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"2.3.4.5"}},
|
|
{RecordType: "AAAA", DNSName: "node1", Targets: endpoint.Targets{"2001:DB8::9"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with neither external nor internal IP returns no endpoints",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{},
|
|
expectError: true,
|
|
},
|
|
{
|
|
title: "node with target annotation",
|
|
nodeName: "node1.example.org",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
"external-dns.alpha.kubernetes.io/target": "203.2.45.7",
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1.example.org", Targets: endpoint.Targets{"203.2.45.7"}},
|
|
},
|
|
},
|
|
{
|
|
title: "annotated node without annotation filter returns endpoint",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
"service.beta.kubernetes.io/external-traffic": "OnlyLocal",
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "annotated node with matching annotation filter returns endpoint",
|
|
annotationFilter: "service.beta.kubernetes.io/external-traffic in (Global, OnlyLocal)",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
"service.beta.kubernetes.io/external-traffic": "OnlyLocal",
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "annotated node with non-matching annotation filter returns nothing",
|
|
annotationFilter: "service.beta.kubernetes.io/external-traffic in (Global, OnlyLocal)",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
"service.beta.kubernetes.io/external-traffic": "SomethingElse",
|
|
},
|
|
expected: []*endpoint.Endpoint{},
|
|
},
|
|
{
|
|
title: "labeled node with matching label selector returns endpoint",
|
|
labelSelector: "service.beta.kubernetes.io/external-traffic in (Global, OnlyLocal)",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
labels: map[string]string{
|
|
"service.beta.kubernetes.io/external-traffic": "OnlyLocal",
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "labeled node with non-matching label selector returns nothing",
|
|
labelSelector: "service.beta.kubernetes.io/external-traffic in (Global, OnlyLocal)",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
labels: map[string]string{
|
|
"service.beta.kubernetes.io/external-traffic": "SomethingElse",
|
|
},
|
|
expected: []*endpoint.Endpoint{},
|
|
},
|
|
{
|
|
title: "our controller type is dns-controller",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
controllerAnnotationKey: controllerAnnotationValue,
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
},
|
|
{
|
|
title: "different controller types are ignored",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
controllerAnnotationKey: "not-dns-controller",
|
|
},
|
|
expected: []*endpoint.Endpoint{},
|
|
},
|
|
{
|
|
title: "ttl not annotated should have RecordTTL.IsConfigured set to false",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}, RecordTTL: endpoint.TTL(0)},
|
|
},
|
|
},
|
|
{
|
|
title: "ttl annotated but invalid should have RecordTTL.IsConfigured set to false",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
ttlAnnotationKey: "foo",
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}, RecordTTL: endpoint.TTL(0)},
|
|
},
|
|
},
|
|
{
|
|
title: "ttl annotated and is valid should set Record.TTL",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
annotations: map[string]string{
|
|
ttlAnnotationKey: "10",
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}, RecordTTL: endpoint.TTL(10)},
|
|
},
|
|
},
|
|
{
|
|
title: "unschedulable node return nothing with excludeUnschedulable=true",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
unschedulable: true,
|
|
excludeUnschedulable: true,
|
|
expected: []*endpoint.Endpoint{},
|
|
expectedLogs: []string{
|
|
"Skipping node node1 because it is unschedulable",
|
|
},
|
|
},
|
|
{
|
|
title: "unschedulable node returns node with excludeUnschedulable=false",
|
|
nodeName: "node1",
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}},
|
|
unschedulable: true,
|
|
excludeUnschedulable: false,
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
},
|
|
expectedAbsentLogs: []string{
|
|
"Skipping node node1 because it is unschedulable",
|
|
},
|
|
},
|
|
} {
|
|
tc := tc
|
|
t.Run(tc.title, func(t *testing.T) {
|
|
var buf *bytes.Buffer
|
|
if len(tc.expectedLogs) == 0 && len(tc.expectedAbsentLogs) == 0 {
|
|
t.Parallel()
|
|
} else {
|
|
buf = testutils.LogsToBuffer(log.DebugLevel, t)
|
|
}
|
|
|
|
labelSelector := labels.Everything()
|
|
if tc.labelSelector != "" {
|
|
var err error
|
|
labelSelector, err = labels.Parse(tc.labelSelector)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Create a Kubernetes testing client
|
|
kubernetes := fake.NewSimpleClientset()
|
|
|
|
node := &v1.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: tc.nodeName,
|
|
Labels: tc.labels,
|
|
Annotations: tc.annotations,
|
|
},
|
|
Spec: v1.NodeSpec{
|
|
Unschedulable: tc.unschedulable,
|
|
},
|
|
Status: v1.NodeStatus{
|
|
Addresses: tc.nodeAddresses,
|
|
},
|
|
}
|
|
|
|
_, err := kubernetes.CoreV1().Nodes().Create(context.Background(), node, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
// Create our object under test and get the endpoints.
|
|
client, err := NewNodeSource(
|
|
context.TODO(),
|
|
kubernetes,
|
|
tc.annotationFilter,
|
|
tc.fqdnTemplate,
|
|
labelSelector,
|
|
tc.exposeInternalIPv6,
|
|
tc.excludeUnschedulable,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
endpoints, err := client.Endpoints(context.Background())
|
|
if tc.expectError {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Validate returned endpoints against desired endpoints.
|
|
validateEndpoints(t, endpoints, tc.expected)
|
|
|
|
for _, entry := range tc.expectedLogs {
|
|
assert.Contains(t, buf.String(), entry)
|
|
}
|
|
|
|
for _, entry := range tc.expectedAbsentLogs {
|
|
assert.NotContains(t, buf.String(), entry)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func testNodeEndpointsWithIPv6(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
title string
|
|
annotationFilter string
|
|
labelSelector string
|
|
fqdnTemplate string
|
|
nodeName string
|
|
nodeAddresses []v1.NodeAddress
|
|
labels map[string]string
|
|
annotations map[string]string
|
|
excludeUnschedulable bool // defaults to false
|
|
exposeInternalIPv6 bool // default to true for this version. Change later when the next minor version is released.
|
|
unschedulable bool // default to false
|
|
expected []*endpoint.Endpoint
|
|
expectError bool
|
|
}{
|
|
{
|
|
title: "node with only internal IPs should return internal IPvs irrespective of exposeInternalIPv6",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: false,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeInternalIP, Address: "2.3.4.5"}, {Type: v1.NodeInternalIP, Address: "2001:DB8::9"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"2.3.4.5"}},
|
|
{RecordType: "AAAA", DNSName: "node1", Targets: endpoint.Targets{"2001:DB8::9"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with both external, internal, and IPv6 IP returns endpoints with external IPs",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: false,
|
|
nodeAddresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "1.2.3.4"}, {
|
|
Type: v1.NodeExternalIP,
|
|
Address: "2001:DB8::8",
|
|
}, {Type: v1.NodeInternalIP, Address: "2001:DB8::9"}},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.4"}},
|
|
{RecordType: "AAAA", DNSName: "node1", Targets: endpoint.Targets{"2001:DB8::8"}},
|
|
},
|
|
},
|
|
{
|
|
title: "node with both external and internal IPs should return internal IPv6 if exposeInternalIPv6 is true",
|
|
nodeName: "node1",
|
|
exposeInternalIPv6: true,
|
|
nodeAddresses: []v1.NodeAddress{
|
|
{Type: v1.NodeExternalIP, Address: "1.2.3.5"},
|
|
{Type: v1.NodeInternalIP, Address: "2001:DB8::9"},
|
|
},
|
|
expected: []*endpoint.Endpoint{
|
|
{RecordType: "A", DNSName: "node1", Targets: endpoint.Targets{"1.2.3.5"}},
|
|
{RecordType: "AAAA", DNSName: "node1", Targets: endpoint.Targets{"2001:DB8::9"}},
|
|
},
|
|
},
|
|
} {
|
|
labelSelector := labels.Everything()
|
|
if tc.labelSelector != "" {
|
|
var err error
|
|
labelSelector, err = labels.Parse(tc.labelSelector)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// Create a Kubernetes testing client
|
|
kubernetes := fake.NewSimpleClientset()
|
|
|
|
node := &v1.Node{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: tc.nodeName,
|
|
Labels: tc.labels,
|
|
Annotations: tc.annotations,
|
|
},
|
|
Spec: v1.NodeSpec{
|
|
Unschedulable: tc.unschedulable,
|
|
},
|
|
Status: v1.NodeStatus{
|
|
Addresses: tc.nodeAddresses,
|
|
},
|
|
}
|
|
|
|
_, err := kubernetes.CoreV1().Nodes().Create(context.Background(), node, metav1.CreateOptions{})
|
|
require.NoError(t, err)
|
|
|
|
var buf *bytes.Buffer
|
|
if tc.exposeInternalIPv6 {
|
|
buf = testutils.LogsToBuffer(log.WarnLevel, t)
|
|
}
|
|
|
|
// Create our object under test and get the endpoints.
|
|
client, err := NewNodeSource(
|
|
context.TODO(),
|
|
kubernetes,
|
|
tc.annotationFilter,
|
|
tc.fqdnTemplate,
|
|
labelSelector,
|
|
tc.exposeInternalIPv6,
|
|
tc.excludeUnschedulable,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
endpoints, err := client.Endpoints(context.Background())
|
|
if tc.expectError {
|
|
require.Error(t, err)
|
|
} else {
|
|
require.NoError(t, err)
|
|
|
|
if tc.exposeInternalIPv6 && buf != nil {
|
|
assert.Contains(t, buf.String(), warningMsg)
|
|
}
|
|
}
|
|
|
|
// Validate returned endpoints against desired endpoints.
|
|
validateEndpoints(t, endpoints, tc.expected)
|
|
}
|
|
}
|