Skip to content

Commit 01e466f

Browse files
committed
feat(service): reconcile DNS records for LoadBalancer Services
- Reconcile DNS records based on the hostname annotation on LoadBalancer Services using VPCNetworkConfiguration allowed DNS zones - Report DNSRecordReady condition for DNS zone validation errors and generic DNS build errors
1 parent a0f2f0b commit 01e466f

26 files changed

Lines changed: 2531 additions & 194 deletions

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ func startServiceController(mgr manager.Manager, nsxClient *nsx.Client) {
247247
subnetport.NewSubnetPortReconciler(mgr, subnetPortService, subnetService, vpcService, ipAddressAllocationService),
248248
pod.NewPodReconciler(mgr, subnetPortService, subnetService, vpcService, nodeService),
249249
networkpolicycontroller.NewNetworkPolicyReconciler(mgr, commonService, vpcService),
250-
service.NewServiceLbReconciler(mgr, commonService),
250+
service.NewServiceLbReconciler(mgr, commonService, dnsRecordService),
251251
subnetbindingcontroller.NewReconciler(mgr, subnetService, subnetBindingService),
252252
subnetipreservationcontroller.NewReconciler(mgr, subnetIPReservationService, subnetService),
253253
)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ require (
5656
require (
5757
github.com/gofrs/uuid v4.4.0+incompatible
5858
go.uber.org/mock v0.6.0
59+
sigs.k8s.io/gateway-api v1.5.1
5960
)
6061

6162
require (
@@ -113,7 +114,6 @@ require (
113114
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
114115
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
115116
github.com/onsi/ginkgo/v2 v2.28.1 // indirect
116-
github.com/onsi/gomega v1.39.1 // indirect
117117
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
118118
github.com/prometheus/client_model v0.6.2 // indirect
119119
github.com/prometheus/common v0.67.5 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUo
420420
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
421421
sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=
422422
sigs.k8s.io/controller-runtime v0.23.3/go.mod h1:B6COOxKptp+YaUT5q4l6LqUJTRpizbgf9KSRNdQGns0=
423+
sigs.k8s.io/gateway-api v1.5.1 h1:RqVRIlkhLhUO8wOHKTLnTJA6o/1un4po4/6M1nRzdd0=
424+
sigs.k8s.io/gateway-api v1.5.1/go.mod h1:GvCETiaMAlLym5CovLxGjS0NysqFk3+Yuq3/rh6QL2o=
423425
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg=
424426
sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
425427
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=

pkg/controllers/service/service_lb_controller.go

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package service
55

66
import (
77
"context"
8+
"fmt"
89
"time"
910

1011
v1 "k8s.io/api/core/v1"
@@ -15,15 +16,20 @@ import (
1516
"k8s.io/client-go/rest"
1617
"k8s.io/client-go/tools/record"
1718
ctrl "sigs.k8s.io/controller-runtime"
19+
"sigs.k8s.io/controller-runtime/pkg/builder"
1820
"sigs.k8s.io/controller-runtime/pkg/client"
1921
"sigs.k8s.io/controller-runtime/pkg/controller"
22+
"sigs.k8s.io/controller-runtime/pkg/handler"
23+
"sigs.k8s.io/controller-runtime/pkg/manager"
2024
"sigs.k8s.io/controller-runtime/pkg/webhook"
2125

26+
"github.com/vmware-tanzu/nsx-operator/pkg/apis/vpc/v1alpha1"
2227
"github.com/vmware-tanzu/nsx-operator/pkg/controllers/common"
2328
"github.com/vmware-tanzu/nsx-operator/pkg/logger"
2429
"github.com/vmware-tanzu/nsx-operator/pkg/metrics"
2530
_ "github.com/vmware-tanzu/nsx-operator/pkg/nsx/ratelimiter"
2631
servicecommon "github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/common"
32+
"github.com/vmware-tanzu/nsx-operator/pkg/nsx/services/dns"
2733
)
2834

2935
var (
@@ -38,6 +44,7 @@ type ServiceLbReconciler struct {
3844
Client client.Client
3945
Scheme *apimachineryruntime.Scheme
4046
Service *servicecommon.Service
47+
DNS dns.DNSRecordProvider
4148
Recorder record.EventRecorder
4249
}
4350

@@ -53,6 +60,14 @@ func updateSuccess(r *ServiceLbReconciler, c context.Context, lbService *v1.Serv
5360
return err
5461
}
5562

63+
func (r *ServiceLbReconciler) deleteDNSForService(ctx context.Context, namespace, name string, op string) error {
64+
if _, err := r.DNS.DeleteRecordByOwnerNN(ctx, dns.ResourceKindService, namespace, name); err != nil {
65+
log.Error(err, "Failed to delete DNS records for Service", "Namespace", namespace, "Name", name, "Operation", op)
66+
return fmt.Errorf("deleting DNS records for %s: %w", op, err)
67+
}
68+
return nil
69+
}
70+
5671
func (r *ServiceLbReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
5772
service := &v1.Service{}
5873
startTime := time.Now()
@@ -63,25 +78,36 @@ func (r *ServiceLbReconciler) Reconcile(ctx context.Context, req ctrl.Request) (
6378
if err := r.Client.Get(ctx, req.NamespacedName, service); err != nil {
6479
if apierrors.IsNotFound(err) {
6580
log.Info("Not found LB service", "req", req.NamespacedName)
66-
return ResultNormal, client.IgnoreNotFound(err)
81+
if err := r.deleteDNSForService(ctx, req.Namespace, req.Name, "deleted Service"); err != nil {
82+
return common.ResultRequeueAfter10sec, err
83+
}
84+
return ResultNormal, nil
6785
}
6886
log.Error(err, "Failed to fetch LB service", "req", req.NamespacedName)
6987
return common.ResultRequeueAfter10sec, err
7088
}
7189

72-
if service.Spec.Type == v1.ServiceTypeLoadBalancer {
73-
log.Info("Reconciling LB service", "LBService", req.NamespacedName)
74-
log.Debug("Reconciling LB Service", "name", service.Name, "version", service.ResourceVersion, "status", service.Status)
75-
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType)
76-
77-
if service.ObjectMeta.DeletionTimestamp.IsZero() {
78-
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType)
79-
err := updateSuccess(r, ctx, service)
80-
if err != nil {
81-
log.Error(err, "Failed to update LB service", "Name", service.Name, "Namespace", service.Namespace)
82-
return common.ResultRequeueAfter10sec, err
83-
}
90+
if service.Spec.Type != v1.ServiceTypeLoadBalancer || !service.ObjectMeta.DeletionTimestamp.IsZero() {
91+
// Try to delete DNS records for Service when it is not a LoadBalancer or is marked for deletion
92+
if err := r.clearDNSAndConditionForService(ctx, req.NamespacedName, "non-LB or terminating Service"); err != nil {
93+
return common.ResultRequeueAfter10sec, err
8494
}
95+
return ResultNormal, nil
96+
}
97+
98+
log.Info("Reconciling LB service", "LBService", req.NamespacedName)
99+
log.Debug("Reconciling LB Service", "name", service.Name, "version", service.ResourceVersion, "status", service.Status)
100+
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerSyncTotal, MetricResType)
101+
102+
if err := r.reconcileLoadBalancerServiceDNS(ctx, service); err != nil {
103+
log.Error(err, "Failed to reconcile DNS for LoadBalancer Service", "Name", service.Name, "Namespace", service.Namespace)
104+
return common.ResultRequeueAfter10sec, fmt.Errorf("reconciling DNS: %w", err)
105+
}
106+
107+
metrics.CounterInc(r.Service.NSXConfig, metrics.ControllerUpdateTotal, MetricResType)
108+
if err := updateSuccess(r, ctx, service); err != nil {
109+
log.Error(err, "Failed to update LB service", "Name", service.Name, "Namespace", service.Namespace)
110+
return common.ResultRequeueAfter10sec, fmt.Errorf("updating LB service: %w", err)
85111
}
86112

87113
return ResultNormal, nil
@@ -119,13 +145,18 @@ func (r *ServiceLbReconciler) setServiceLbStatus(ctx context.Context, lbService
119145
}
120146

121147
func (r *ServiceLbReconciler) setupWithManager(mgr ctrl.Manager) error {
122-
return ctrl.NewControllerManagedBy(mgr).
148+
b := ctrl.NewControllerManagedBy(mgr).
123149
For(&v1.Service{}).
150+
Watches(
151+
&v1alpha1.NetworkInfo{},
152+
handler.EnqueueRequestsFromMapFunc(r.enqueueLBServiceRequestsFromNetworkInfo),
153+
builder.WithPredicates(predicateNetworkInfoAllowedDNSDomainsChanged()),
154+
).
124155
WithOptions(
125156
controller.Options{
126157
MaxConcurrentReconciles: common.NumReconcile(),
127-
}).
128-
Complete(r)
158+
})
159+
return b.Complete(r)
129160
}
130161

131162
// Start setup manager
@@ -172,18 +203,36 @@ func (r *ServiceLbReconciler) StartController(mgr ctrl.Manager, _ webhook.Server
172203
log.Error(err, "Failed to create controller", "controller", "ServiceLb")
173204
return err
174205
}
206+
err := mgr.Add(manager.RunnableFunc(func(ctx context.Context) error {
207+
stop := make(chan bool)
208+
go func() {
209+
<-ctx.Done()
210+
close(stop)
211+
}()
212+
common.GenericGarbageCollector(stop, servicecommon.GCInterval, r.CollectGarbage)
213+
return nil
214+
}))
215+
if err != nil {
216+
log.Error(err, "Failed to add LB GC to manager")
217+
return err
218+
}
175219
return nil
176220
}
177221

178222
func (r *ServiceLbReconciler) CollectGarbage(ctx context.Context) error {
179-
return nil
223+
return r.collectDNSGarbage(ctx)
180224
}
181225

182-
func NewServiceLbReconciler(mgr ctrl.Manager, commonService servicecommon.Service) *ServiceLbReconciler {
226+
func NewServiceLbReconciler(mgr ctrl.Manager, commonService servicecommon.Service, dnsRecordService *dns.DNSRecordService) *ServiceLbReconciler {
183227
if isServiceLbStatusIpModeSupported(mgr.GetConfig()) {
228+
var dnsProv dns.DNSRecordProvider
229+
if dnsRecordService != nil {
230+
dnsProv = dnsRecordService
231+
}
184232
serviceLbReconciler := &ServiceLbReconciler{
185233
Client: mgr.GetClient(),
186234
Scheme: mgr.GetScheme(),
235+
DNS: dnsProv,
187236
Recorder: mgr.GetEventRecorderFor("serviceLb-controller"), //nolint:staticcheck // record.EventRecorder; StatusUpdater not on events.EventRecorder yet
188237
}
189238
serviceLbReconciler.Service = &commonService

0 commit comments

Comments
 (0)