Skip to content

Commit 275715d

Browse files
authored
feat(source/f5-virtual-server): add host aliases support for Virtual … (#5745)
* feat(source/f5-virtual-server): add host aliases support for Virtual Server source * fix: markdown lint * fix: markdown lint * refactor(source/f5_virtualserver): remove if check for array length, already taken care of by the iterator
1 parent 7792e78 commit 275715d

File tree

3 files changed

+304
-1
lines changed

3 files changed

+304
-1
lines changed

docs/sources/f5-virtualserver.md

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
This tutorial describes how to configure ExternalDNS to use the F5 Networks VirtualServer Source. It is meant to supplement the other provider-specific setup tutorials.
44

55
The F5 Networks VirtualServer CRD is part of [this](https://github.com/F5Networks/k8s-bigip-ctlr) project.
6-
See more in-depth info regarding the VirtualServer CRD [here](https://github.com/F5Networks/k8s-bigip-ctlr/blob/master/docs/config_examples/customResource/CustomResource.md#virtualserver).
6+
See more in-depth info regarding the VirtualServer CRD [in the official documentation](https://github.com/F5Networks/k8s-bigip-ctlr/blob/master/docs/config_examples/customResource/CustomResource.md#virtualserver).
77

88
## Start with ExternalDNS with the F5 Networks VirtualServer source
99

@@ -37,3 +37,57 @@ Note that, in case you're not installing via Helm, you'll need the following in
3737
- list
3838
- watch
3939
```
40+
41+
## How it works
42+
43+
The F5 VirtualServer source creates DNS records based on the following fields:
44+
45+
- **`spec.host`**: The primary hostname for the virtual server
46+
- **`spec.hostAliases`**: Additional hostnames that should also resolve to the same targets
47+
- **`spec.virtualServerAddress`**: The IP address to use as the target (if no target annotation is set)
48+
- **`status.vsAddress`**: The IP address from the status field (if no spec address or target annotation is set)
49+
50+
### Example VirtualServer with hostAliases
51+
52+
```yaml
53+
apiVersion: cis.f5.com/v1
54+
kind: VirtualServer
55+
metadata:
56+
name: example-vs
57+
namespace: default
58+
spec:
59+
host: www.example.com
60+
hostAliases:
61+
- alias1.example.com
62+
- alias2.example.com
63+
virtualServerAddress: 192.168.1.100
64+
```
65+
66+
This configuration will create DNS A records for:
67+
68+
- `www.example.com` → `192.168.1.100`
69+
- `alias1.example.com` → `192.168.1.100`
70+
- `alias2.example.com` → `192.168.1.100`
71+
72+
### Target Priority
73+
74+
The source follows this priority order for determining targets:
75+
76+
1. **Target annotation**: `external-dns.alpha.kubernetes.io/target` (highest priority)
77+
2. **Spec address**: `spec.virtualServerAddress`
78+
3. **Status address**: `status.vsAddress`
79+
80+
If none of these are available, the VirtualServer will be skipped.
81+
82+
### TTL Support
83+
84+
You can set a custom TTL using the annotation:
85+
86+
```yaml
87+
annotations:
88+
external-dns.alpha.kubernetes.io/ttl: "300"
89+
```
90+
91+
### Annotation Filtering
92+
93+
You can filter VirtualServers using the `--annotation-filter` flag to only process those with specific annotations.

source/f5_virtualserver.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ func (vs *f5VirtualServerSource) endpointsFromVirtualServers(virtualServers []*f
169169
}
170170

171171
endpoints = append(endpoints, EndpointsForHostname(virtualServer.Spec.Host, targets, ttl, nil, "", resource)...)
172+
173+
for _, alias := range virtualServer.Spec.HostAliases {
174+
if alias != "" {
175+
endpoints = append(endpoints, EndpointsForHostname(alias, targets, ttl, nil, "", resource)...)
176+
}
177+
}
172178
}
173179

174180
return endpoints, nil

source/f5_virtualserver_test.go

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,249 @@ func TestF5VirtualServerEndpoints(t *testing.T) {
325325
},
326326
expected: nil,
327327
},
328+
{
329+
name: "F5 VirtualServer with hostAliases",
330+
virtualServer: f5.VirtualServer{
331+
TypeMeta: metav1.TypeMeta{
332+
APIVersion: f5VirtualServerGVR.GroupVersion().String(),
333+
Kind: "VirtualServer",
334+
},
335+
ObjectMeta: metav1.ObjectMeta{
336+
Name: "test-vs",
337+
Namespace: defaultF5VirtualServerNamespace,
338+
},
339+
Spec: f5.VirtualServerSpec{
340+
Host: "www.example.com",
341+
VirtualServerAddress: "192.168.1.100",
342+
HostAliases: []string{"alias1.example.com", "alias2.example.com"},
343+
},
344+
Status: f5.CustomResourceStatus{
345+
VSAddress: "192.168.1.100",
346+
Status: "OK",
347+
},
348+
},
349+
expected: []*endpoint.Endpoint{
350+
{
351+
DNSName: "www.example.com",
352+
Targets: []string{"192.168.1.100"},
353+
RecordType: endpoint.RecordTypeA,
354+
RecordTTL: 0,
355+
Labels: endpoint.Labels{
356+
"resource": "f5-virtualserver/virtualserver/test-vs",
357+
},
358+
},
359+
{
360+
DNSName: "alias1.example.com",
361+
Targets: []string{"192.168.1.100"},
362+
RecordType: endpoint.RecordTypeA,
363+
RecordTTL: 0,
364+
Labels: endpoint.Labels{
365+
"resource": "f5-virtualserver/virtualserver/test-vs",
366+
},
367+
},
368+
{
369+
DNSName: "alias2.example.com",
370+
Targets: []string{"192.168.1.100"},
371+
RecordType: endpoint.RecordTypeA,
372+
RecordTTL: 0,
373+
Labels: endpoint.Labels{
374+
"resource": "f5-virtualserver/virtualserver/test-vs",
375+
},
376+
},
377+
},
378+
},
379+
{
380+
name: "F5 VirtualServer with hostAliases and target annotation",
381+
virtualServer: f5.VirtualServer{
382+
TypeMeta: metav1.TypeMeta{
383+
APIVersion: f5VirtualServerGVR.GroupVersion().String(),
384+
Kind: "VirtualServer",
385+
},
386+
ObjectMeta: metav1.ObjectMeta{
387+
Name: "test-vs",
388+
Namespace: defaultF5VirtualServerNamespace,
389+
Annotations: map[string]string{
390+
targetAnnotationKey: "192.168.1.150",
391+
},
392+
},
393+
Spec: f5.VirtualServerSpec{
394+
Host: "www.example.com",
395+
VirtualServerAddress: "192.168.1.100",
396+
HostAliases: []string{"alias1.example.com", "alias2.example.com"},
397+
},
398+
Status: f5.CustomResourceStatus{
399+
VSAddress: "192.168.1.100",
400+
Status: "OK",
401+
},
402+
},
403+
expected: []*endpoint.Endpoint{
404+
{
405+
DNSName: "www.example.com",
406+
Targets: []string{"192.168.1.150"},
407+
RecordType: endpoint.RecordTypeA,
408+
RecordTTL: 0,
409+
Labels: endpoint.Labels{
410+
"resource": "f5-virtualserver/virtualserver/test-vs",
411+
},
412+
},
413+
{
414+
DNSName: "alias1.example.com",
415+
Targets: []string{"192.168.1.150"},
416+
RecordType: endpoint.RecordTypeA,
417+
RecordTTL: 0,
418+
Labels: endpoint.Labels{
419+
"resource": "f5-virtualserver/virtualserver/test-vs",
420+
},
421+
},
422+
{
423+
DNSName: "alias2.example.com",
424+
Targets: []string{"192.168.1.150"},
425+
RecordType: endpoint.RecordTypeA,
426+
RecordTTL: 0,
427+
Labels: endpoint.Labels{
428+
"resource": "f5-virtualserver/virtualserver/test-vs",
429+
},
430+
},
431+
},
432+
},
433+
{
434+
name: "F5 VirtualServer with hostAliases and TTL annotation",
435+
virtualServer: f5.VirtualServer{
436+
TypeMeta: metav1.TypeMeta{
437+
APIVersion: f5VirtualServerGVR.GroupVersion().String(),
438+
Kind: "VirtualServer",
439+
},
440+
ObjectMeta: metav1.ObjectMeta{
441+
Name: "test-vs",
442+
Namespace: defaultF5VirtualServerNamespace,
443+
Annotations: map[string]string{
444+
"external-dns.alpha.kubernetes.io/ttl": "300",
445+
},
446+
},
447+
Spec: f5.VirtualServerSpec{
448+
Host: "www.example.com",
449+
VirtualServerAddress: "192.168.1.100",
450+
HostAliases: []string{"alias1.example.com", "alias2.example.com"},
451+
},
452+
Status: f5.CustomResourceStatus{
453+
VSAddress: "192.168.1.100",
454+
Status: "OK",
455+
},
456+
},
457+
expected: []*endpoint.Endpoint{
458+
{
459+
DNSName: "www.example.com",
460+
Targets: []string{"192.168.1.100"},
461+
RecordType: endpoint.RecordTypeA,
462+
RecordTTL: 300,
463+
Labels: endpoint.Labels{
464+
"resource": "f5-virtualserver/virtualserver/test-vs",
465+
},
466+
},
467+
{
468+
DNSName: "alias1.example.com",
469+
Targets: []string{"192.168.1.100"},
470+
RecordType: endpoint.RecordTypeA,
471+
RecordTTL: 300,
472+
Labels: endpoint.Labels{
473+
"resource": "f5-virtualserver/virtualserver/test-vs",
474+
},
475+
},
476+
{
477+
DNSName: "alias2.example.com",
478+
Targets: []string{"192.168.1.100"},
479+
RecordType: endpoint.RecordTypeA,
480+
RecordTTL: 300,
481+
Labels: endpoint.Labels{
482+
"resource": "f5-virtualserver/virtualserver/test-vs",
483+
},
484+
},
485+
},
486+
},
487+
{
488+
name: "F5 VirtualServer with empty hostAliases",
489+
virtualServer: f5.VirtualServer{
490+
TypeMeta: metav1.TypeMeta{
491+
APIVersion: f5VirtualServerGVR.GroupVersion().String(),
492+
Kind: "VirtualServer",
493+
},
494+
ObjectMeta: metav1.ObjectMeta{
495+
Name: "test-vs",
496+
Namespace: defaultF5VirtualServerNamespace,
497+
},
498+
Spec: f5.VirtualServerSpec{
499+
Host: "www.example.com",
500+
VirtualServerAddress: "192.168.1.100",
501+
HostAliases: []string{},
502+
},
503+
Status: f5.CustomResourceStatus{
504+
VSAddress: "192.168.1.100",
505+
Status: "OK",
506+
},
507+
},
508+
expected: []*endpoint.Endpoint{
509+
{
510+
DNSName: "www.example.com",
511+
Targets: []string{"192.168.1.100"},
512+
RecordType: endpoint.RecordTypeA,
513+
RecordTTL: 0,
514+
Labels: endpoint.Labels{
515+
"resource": "f5-virtualserver/virtualserver/test-vs",
516+
},
517+
},
518+
},
519+
},
520+
{
521+
name: "F5 VirtualServer with hostAliases containing empty strings",
522+
virtualServer: f5.VirtualServer{
523+
TypeMeta: metav1.TypeMeta{
524+
APIVersion: f5VirtualServerGVR.GroupVersion().String(),
525+
Kind: "VirtualServer",
526+
},
527+
ObjectMeta: metav1.ObjectMeta{
528+
Name: "test-vs",
529+
Namespace: defaultF5VirtualServerNamespace,
530+
},
531+
Spec: f5.VirtualServerSpec{
532+
Host: "www.example.com",
533+
VirtualServerAddress: "192.168.1.100",
534+
HostAliases: []string{"alias1.example.com", "", "alias2.example.com"},
535+
},
536+
Status: f5.CustomResourceStatus{
537+
VSAddress: "192.168.1.100",
538+
Status: "OK",
539+
},
540+
},
541+
expected: []*endpoint.Endpoint{
542+
{
543+
DNSName: "www.example.com",
544+
Targets: []string{"192.168.1.100"},
545+
RecordType: endpoint.RecordTypeA,
546+
RecordTTL: 0,
547+
Labels: endpoint.Labels{
548+
"resource": "f5-virtualserver/virtualserver/test-vs",
549+
},
550+
},
551+
{
552+
DNSName: "alias1.example.com",
553+
Targets: []string{"192.168.1.100"},
554+
RecordType: endpoint.RecordTypeA,
555+
RecordTTL: 0,
556+
Labels: endpoint.Labels{
557+
"resource": "f5-virtualserver/virtualserver/test-vs",
558+
},
559+
},
560+
{
561+
DNSName: "alias2.example.com",
562+
Targets: []string{"192.168.1.100"},
563+
RecordType: endpoint.RecordTypeA,
564+
RecordTTL: 0,
565+
Labels: endpoint.Labels{
566+
"resource": "f5-virtualserver/virtualserver/test-vs",
567+
},
568+
},
569+
},
570+
},
328571
}
329572

330573
for _, tc := range tests {

0 commit comments

Comments
 (0)