Skip to content

Commit 0aababa

Browse files
feat(source/node): fqdn support combineFQDNAnnotation (kubernetes-sigs#5526)
Signed-off-by: ivan katliarchuk <[email protected]>
1 parent 8ce0b3d commit 0aababa

File tree

5 files changed

+93
-29
lines changed

5 files changed

+93
-29
lines changed

docs/advanced/fqdn-templating.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The template uses the following data from the source object (e.g., a `Service` o
5454
| `istio-gateway` | Queries Istio Gateway resources for endpoints. |||
5555
| `istio-virtualservice` | Queries Istio VirtualService resources for endpoints. |||
5656
| `kong-tcpingress` | Queries Kong TCPIngress resources for endpoints. |||
57-
| `node` | Queries Kubernetes Node resources for endpoints. || |
57+
| `node` | Queries Kubernetes Node resources for endpoints. || |
5858
| `openshift-route` | Queries OpenShift Route resources for endpoints. |||
5959
| `pod` | Queries Kubernetes Pod resources for endpoints. |||
6060
| `service` | Queries Kubernetes Service resources for endpoints. |||

source/node.go

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,26 @@ import (
3838
const warningMsg = "The default behavior of exposing internal IPv6 addresses will change in the next minor version. Use --no-expose-internal-ipv6 flag to opt-in to the new behavior."
3939

4040
type nodeSource struct {
41-
client kubernetes.Interface
42-
annotationFilter string
43-
fqdnTemplate *template.Template
41+
client kubernetes.Interface
42+
annotationFilter string
43+
fqdnTemplate *template.Template
44+
combineFQDNAnnotation bool
45+
4446
nodeInformer coreinformers.NodeInformer
4547
labelSelector labels.Selector
4648
excludeUnschedulable bool
4749
exposeInternalIPv6 bool
4850
}
4951

5052
// NewNodeSource creates a new nodeSource with the given config.
51-
func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotationFilter, fqdnTemplate string, labelSelector labels.Selector, exposeInternalIPv6, excludeUnschedulable bool) (Source, error) {
53+
func NewNodeSource(
54+
ctx context.Context,
55+
kubeClient kubernetes.Interface,
56+
annotationFilter, fqdnTemplate string,
57+
labelSelector labels.Selector,
58+
exposeInternalIPv6,
59+
excludeUnschedulable bool,
60+
combineFQDNAnnotation bool) (Source, error) {
5261
tmpl, err := fqdn.ParseTemplate(fqdnTemplate)
5362
if err != nil {
5463
return nil, err
@@ -76,18 +85,19 @@ func NewNodeSource(ctx context.Context, kubeClient kubernetes.Interface, annotat
7685
}
7786

7887
return &nodeSource{
79-
client: kubeClient,
80-
annotationFilter: annotationFilter,
81-
fqdnTemplate: tmpl,
82-
nodeInformer: nodeInformer,
83-
labelSelector: labelSelector,
84-
excludeUnschedulable: excludeUnschedulable,
85-
exposeInternalIPv6: exposeInternalIPv6,
88+
client: kubeClient,
89+
annotationFilter: annotationFilter,
90+
fqdnTemplate: tmpl,
91+
combineFQDNAnnotation: combineFQDNAnnotation,
92+
nodeInformer: nodeInformer,
93+
labelSelector: labelSelector,
94+
excludeUnschedulable: excludeUnschedulable,
95+
exposeInternalIPv6: exposeInternalIPv6,
8696
}, nil
8797
}
8898

8999
// Endpoints returns endpoint objects for each service that should be processed.
90-
func (ns *nodeSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, error) {
100+
func (ns *nodeSource) Endpoints(_ context.Context) ([]*endpoint.Endpoint, error) {
91101
nodes, err := ns.nodeInformer.Lister().List(ns.labelSelector)
92102
if err != nil {
93103
return nil, err
@@ -127,21 +137,9 @@ func (ns *nodeSource) Endpoints(ctx context.Context) ([]*endpoint.Endpoint, erro
127137
}
128138
}
129139

130-
dnsNames := make(map[string]bool)
131-
132-
if ns.fqdnTemplate != nil {
133-
hostnames, err := fqdn.ExecTemplate(ns.fqdnTemplate, node)
134-
if err != nil {
135-
return nil, err
136-
}
137-
138-
for _, name := range hostnames {
139-
dnsNames[name] = true
140-
log.Debugf("applied template for %s, converting to %s", node.Name, name)
141-
}
142-
} else {
143-
dnsNames[node.Name] = true
144-
log.Debugf("not applying template for %s", node.Name)
140+
dnsNames, err := ns.collectDNSNames(node)
141+
if err != nil {
142+
return nil, err
145143
}
146144

147145
for dns := range dnsNames {
@@ -233,3 +231,36 @@ func (ns *nodeSource) filterByAnnotations(nodes []*v1.Node) ([]*v1.Node, error)
233231

234232
return filteredList, nil
235233
}
234+
235+
// collectDNSNames returns a set of DNS names associated with the given Kubernetes Node.
236+
// If an FQDN template is configured, it renders the template using the Node object
237+
// to generate one or more DNS names.
238+
// If combineFQDNAnnotation is enabled, the Node's name is also included alongside
239+
// the templated names. If no FQDN template is provided, the result will include only
240+
// the Node's name.
241+
//
242+
// Returns an error if template rendering fails.
243+
func (ns *nodeSource) collectDNSNames(node *v1.Node) (map[string]bool, error) {
244+
dnsNames := make(map[string]bool)
245+
// If no FQDN template is configured, fallback to the node name
246+
if ns.fqdnTemplate == nil {
247+
dnsNames[node.Name] = true
248+
return dnsNames, nil
249+
}
250+
251+
names, err := fqdn.ExecTemplate(ns.fqdnTemplate, node)
252+
if err != nil {
253+
return nil, err
254+
}
255+
256+
for _, name := range names {
257+
dnsNames[name] = true
258+
log.Debugf("applied template for %s, converting to %s", node.Name, name)
259+
}
260+
261+
if ns.combineFQDNAnnotation {
262+
dnsNames[node.Name] = true
263+
}
264+
265+
return dnsNames, nil
266+
}

source/node_fqdn_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func TestNodeSourceNewNodeSourceWithFqdn(t *testing.T) {
6464
labels.Everything(),
6565
true,
6666
true,
67+
false,
6768
)
6869
if tt.expectError {
6970
assert.Error(t, err)
@@ -80,6 +81,7 @@ func TestNodeSourceFqdnTemplatingExamples(t *testing.T) {
8081
nodes []*v1.Node
8182
fqdnTemplate string
8283
expected []*endpoint.Endpoint
84+
combineFQDN bool
8385
}{
8486
{
8587
title: "templating expansion with multiple domains",
@@ -293,6 +295,32 @@ func TestNodeSourceFqdnTemplatingExamples(t *testing.T) {
293295
{DNSName: "node-name-2.domain.tld", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"243.186.136.178"}},
294296
},
295297
},
298+
{
299+
title: "templating with shared all domain and fqdn combination annotation",
300+
combineFQDN: true,
301+
nodes: []*v1.Node{
302+
{
303+
ObjectMeta: metav1.ObjectMeta{Name: "node-name-1"},
304+
Status: v1.NodeStatus{
305+
Addresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "243.186.136.160"}},
306+
},
307+
},
308+
{
309+
ObjectMeta: metav1.ObjectMeta{Name: "node-name-2"},
310+
Status: v1.NodeStatus{
311+
Addresses: []v1.NodeAddress{{Type: v1.NodeExternalIP, Address: "243.186.136.178"}},
312+
},
313+
},
314+
},
315+
fqdnTemplate: "{{ .Name }}.domain.tld,all.example.com",
316+
expected: []*endpoint.Endpoint{
317+
{DNSName: "all.example.com", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"243.186.136.160", "243.186.136.178"}},
318+
{DNSName: "node-name-1.domain.tld", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"243.186.136.160"}},
319+
{DNSName: "node-name-2.domain.tld", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"243.186.136.178"}},
320+
{DNSName: "node-name-1", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"243.186.136.160"}},
321+
{DNSName: "node-name-2", RecordType: endpoint.RecordTypeA, Targets: endpoint.Targets{"243.186.136.178"}},
322+
},
323+
},
296324
} {
297325
t.Run(tt.title, func(t *testing.T) {
298326
kubeClient := fake.NewClientset()
@@ -310,6 +338,7 @@ func TestNodeSourceFqdnTemplatingExamples(t *testing.T) {
310338
labels.Everything(),
311339
true,
312340
true,
341+
tt.combineFQDN,
313342
)
314343
require.NoError(t, err)
315344

source/node_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ func testNodeSourceNewNodeSource(t *testing.T) {
9595
labels.Everything(),
9696
true,
9797
true,
98+
false,
9899
)
99100

100101
if ti.expectError {
@@ -440,6 +441,7 @@ func testNodeSourceEndpoints(t *testing.T) {
440441
labelSelector,
441442
tc.exposeInternalIPv6,
442443
tc.excludeUnschedulable,
444+
false,
443445
)
444446
require.NoError(t, err)
445447

@@ -557,6 +559,7 @@ func testNodeEndpointsWithIPv6(t *testing.T) {
557559
labelSelector,
558560
tc.exposeInternalIPv6,
559561
tc.excludeUnschedulable,
562+
false,
560563
)
561564
require.NoError(t, err)
562565

@@ -604,6 +607,7 @@ func TestResourceLabelIsSetForEachNodeEndpoint(t *testing.T) {
604607
labels.Everything(),
605608
false,
606609
true,
610+
false,
607611
)
608612
require.NoError(t, err)
609613

source/store.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ func BuildWithConfig(ctx context.Context, source string, p ClientGenerator, cfg
267267
if err != nil {
268268
return nil, err
269269
}
270-
return NewNodeSource(ctx, client, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.LabelFilter, cfg.ExposeInternalIPv6, cfg.ExcludeUnschedulable)
270+
return NewNodeSource(ctx, client, cfg.AnnotationFilter, cfg.FQDNTemplate, cfg.LabelFilter, cfg.ExposeInternalIPv6, cfg.ExcludeUnschedulable, cfg.CombineFQDNAndAnnotation)
271271
case "service":
272272
client, err := p.KubeClient()
273273
if err != nil {

0 commit comments

Comments
 (0)