Skip to content

Commit 62137b4

Browse files
committed
Correctly pull default listener settings from the underlying gateway in the HTTPProxy reconciler, move the HTTPProxy reconciler to accumulate hostnames based on listeners and their status, instead of addresses.
1 parent 411dec0 commit 62137b4

3 files changed

Lines changed: 98 additions & 54 deletions

File tree

internal/controller/gateway_controller_test.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"slices"
77
"testing"
88

9-
"github.com/davecgh/go-spew/spew"
109
"github.com/stretchr/testify/assert"
1110
corev1 "k8s.io/api/core/v1"
1211
discoveryv1 "k8s.io/api/discovery/v1"
@@ -63,7 +62,6 @@ func TestEnsureDownstreamGateway(t *testing.T) {
6362

6463
}),
6564
assert: func(t *testing.T, upstreamGateway, downstreamGateway *gatewayv1.Gateway) {
66-
spew.Dump(downstreamGateway)
6765
if assert.Len(t, downstreamGateway.Spec.Listeners, 2) {
6866

6967
assert.Equal(t, gatewayv1.PortNumber(DefaultHTTPPort), downstreamGateway.Spec.Listeners[0].Port)

internal/controller/httpproxy_controller.go

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,12 @@ func (r *HTTPProxyReconciler) Reconcile(ctx context.Context, req mcreconcile.Req
135135
if !gateway.CreationTimestamp.IsZero() {
136136
defaultHTTPListener := gatewayutil.GetListenerByName(gateway.Spec.Listeners, gatewayutil.DefaultHTTPListenerName)
137137
if defaultHTTPListener != nil {
138-
desiredResources.gateway.Spec.Listeners = append(desiredResources.gateway.Spec.Listeners, *defaultHTTPListener)
138+
gatewayutil.SetListener(desiredResources.gateway, *defaultHTTPListener)
139139
}
140140

141141
defaultHTTPSListener := gatewayutil.GetListenerByName(gateway.Spec.Listeners, gatewayutil.DefaultHTTPSListenerName)
142142
if defaultHTTPSListener != nil {
143-
desiredResources.gateway.Spec.Listeners = append(desiredResources.gateway.Spec.Listeners, *defaultHTTPSListener)
143+
gatewayutil.SetListener(desiredResources.gateway, *defaultHTTPSListener)
144144
}
145145
}
146146

@@ -276,17 +276,6 @@ func (r *HTTPProxyReconciler) reconcileHTTPProxyHostnameStatus(
276276
logger.Info("updating hostname status")
277277

278278
var hostnames []gatewayv1.Hostname
279-
// Copy over addresses for the TargetDomain, as they are also configured
280-
// as hostnames. Eventually we will also copy over hostnames which have been
281-
// successfully programmed on the HTTPProxy (custom domains need to be added,
282-
// along with validation for them)
283-
for _, address := range gateway.Status.Addresses {
284-
if ptr.Deref(address.Type, gatewayv1.IPAddressType) == gatewayv1.HostnameAddressType &&
285-
strings.HasSuffix(address.Value, r.Config.Gateway.TargetDomain) {
286-
hostnames = append(hostnames, gatewayv1.Hostname(address.Value))
287-
}
288-
}
289-
290279
currentListenerStatus := map[gatewayv1.SectionName]gatewayv1.ListenerStatus{}
291280
for _, listener := range gateway.Status.Listeners {
292281
currentListenerStatus[listener.Name] = *listener.DeepCopy()
@@ -295,31 +284,30 @@ func (r *HTTPProxyReconciler) reconcileHTTPProxyHostnameStatus(
295284
acceptedHostnames := sets.New[gatewayv1.Hostname]()
296285
nonAcceptedHostnames := sets.New[string]()
297286
inUseHostnames := sets.New[string]()
298-
for _, hostname := range httpProxyCopy.Spec.Hostnames {
299-
for _, listener := range gateway.Spec.Listeners {
300-
if listener.Hostname == nil || *listener.Hostname != hostname {
301-
continue
302-
}
303-
304-
listenerStatus, ok := currentListenerStatus[listener.Name]
305-
if !ok {
306-
logger.Info("listener status not found", "listener_name", listener.Name)
307-
continue
308-
}
287+
for _, listener := range gateway.Spec.Listeners {
288+
if listener.Hostname == nil {
289+
// Should only happen shortly after creation, before the default hostnames
290+
// are assigned
291+
continue
292+
}
309293

310-
listenerAcceptedCondition := apimeta.FindStatusCondition(listenerStatus.Conditions, string(gatewayv1.ListenerConditionAccepted))
311-
if listenerAcceptedCondition != nil {
294+
listenerStatus, ok := currentListenerStatus[listener.Name]
295+
if !ok {
296+
logger.Info("listener status not found", "listener_name", listener.Name)
297+
continue
298+
}
312299

313-
if listenerAcceptedCondition.Status == metav1.ConditionTrue {
314-
acceptedHostnames.Insert(hostname)
315-
} else if listenerAcceptedCondition.Reason == networkingv1alpha.HostnameInUseReason {
316-
inUseHostnames.Insert(string(hostname))
317-
} else {
318-
nonAcceptedHostnames.Insert(string(hostname))
319-
}
300+
listenerAcceptedCondition := apimeta.FindStatusCondition(listenerStatus.Conditions, string(gatewayv1.ListenerConditionAccepted))
301+
if listenerAcceptedCondition != nil {
302+
if listenerAcceptedCondition.Status == metav1.ConditionTrue {
303+
acceptedHostnames.Insert(*listener.Hostname)
304+
} else if listenerAcceptedCondition.Reason == networkingv1alpha.HostnameInUseReason {
305+
inUseHostnames.Insert(string(*listener.Hostname))
320306
} else {
321-
nonAcceptedHostnames.Insert(string(hostname))
307+
nonAcceptedHostnames.Insert(string(*listener.Hostname))
322308
}
309+
} else {
310+
nonAcceptedHostnames.Insert(string(*listener.Hostname))
323311
}
324312
}
325313

@@ -340,7 +328,9 @@ func (r *HTTPProxyReconciler) reconcileHTTPProxyHostnameStatus(
340328
hostnamesVerifiedCondition.Status = metav1.ConditionFalse
341329
hostnamesVerifiedCondition.Reason = networkingv1alpha.UnverifiedHostnamesPresent
342330
hostnamesVerifiedCondition.Message = fmt.Sprintf("unverified hostnames present, check status of Domains in the same namespace: %s", strings.Join(nonAcceptedHostnamesSlice, ","))
343-
} else if acceptedHostnames.Len() == len(httpProxyCopy.Spec.Hostnames) {
331+
} else if acceptedHostnames.Len() == len(httpProxyCopy.Spec.Hostnames) || acceptedHostnames.Len() == len(httpProxyCopy.Spec.Hostnames)+1 {
332+
// acceptedHostnames may contain the default listener hostname if it has
333+
// not been removed by the user.
344334
hostnamesVerifiedCondition.Status = metav1.ConditionTrue
345335
hostnamesVerifiedCondition.Reason = networkingv1alpha.HTTPProxyReasonHostnamesVerified
346336
hostnamesVerifiedCondition.Message = "All hostnames have been accepted and programmed"

internal/controller/httpproxy_controller_test.go

Lines changed: 73 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"k8s.io/utils/ptr"
1616
"sigs.k8s.io/controller-runtime/pkg/client"
1717
"sigs.k8s.io/controller-runtime/pkg/client/fake"
18+
"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
1819
"sigs.k8s.io/controller-runtime/pkg/cluster"
1920
"sigs.k8s.io/controller-runtime/pkg/log"
2021
"sigs.k8s.io/controller-runtime/pkg/log/zap"
@@ -25,6 +26,7 @@ import (
2526

2627
networkingv1alpha "go.datum.net/network-services-operator/api/v1alpha"
2728
"go.datum.net/network-services-operator/internal/config"
29+
gatewayutil "go.datum.net/network-services-operator/internal/util/gateway"
2830
)
2931

3032
//nolint:gocyclo
@@ -302,7 +304,8 @@ func TestHTTPProxyReconcile(t *testing.T) {
302304
GatewayClassName: "test-gateway-class",
303305
},
304306
Gateway: config.GatewayConfig{
305-
TargetDomain: "example.com",
307+
ControllerName: gatewayv1.GatewayController("test-gateway-class"),
308+
TargetDomain: "example.com",
306309
ListenerTLSOptions: map[gatewayv1.AnnotationKey]gatewayv1.AnnotationValue{
307310
gatewayv1.AnnotationKey("gateway.networking.datumapis.com/certificate-issuer"): gatewayv1.AnnotationValue("test-issuer"),
308311
},
@@ -312,13 +315,14 @@ func TestHTTPProxyReconcile(t *testing.T) {
312315
type testContext struct {
313316
*testing.T
314317
reconciler *HTTPProxyReconciler
318+
gateway *gatewayv1.Gateway
315319
}
316320

317321
tests := []struct {
318322
name string
319323
httpProxy *networkingv1alpha.HTTPProxy
320324
existingObjects []client.Object
321-
postCreateGatewayStatus *gatewayv1.Gateway
325+
postCreateGatewayStatus func(*gatewayv1.Gateway)
322326
expectedError bool
323327
expectedConditions []metav1.Condition
324328
assert func(t *testContext, cl client.Client, httpProxy *networkingv1alpha.HTTPProxy)
@@ -471,12 +475,12 @@ func TestHTTPProxyReconcile(t *testing.T) {
471475
{
472476
name: "address and hostname propagation",
473477
httpProxy: newHTTPProxy(),
474-
postCreateGatewayStatus: &gatewayv1.Gateway{
475-
Status: gatewayv1.GatewayStatus{
478+
postCreateGatewayStatus: func(g *gatewayv1.Gateway) {
479+
g.Status = gatewayv1.GatewayStatus{
476480
Addresses: []gatewayv1.GatewayStatusAddress{
477481
{
478482
Type: ptr.To(gatewayv1.HostnameAddressType),
479-
Value: "test.example.com",
483+
Value: testConfig.Gateway.GatewayDNSAddress(g),
480484
},
481485
},
482486
Conditions: []metav1.Condition{
@@ -491,7 +495,29 @@ func TestHTTPProxyReconcile(t *testing.T) {
491495
Reason: string(gatewayv1.GatewayReasonProgrammed),
492496
},
493497
},
494-
},
498+
Listeners: []gatewayv1.ListenerStatus{
499+
{
500+
Name: gatewayutil.DefaultHTTPListenerName,
501+
Conditions: []metav1.Condition{
502+
{
503+
Type: string(gatewayv1.GatewayConditionAccepted),
504+
Status: metav1.ConditionTrue,
505+
Reason: string(gatewayv1.GatewayReasonAccepted),
506+
},
507+
},
508+
},
509+
{
510+
Name: gatewayutil.DefaultHTTPSListenerName,
511+
Conditions: []metav1.Condition{
512+
{
513+
Type: string(gatewayv1.GatewayConditionAccepted),
514+
Status: metav1.ConditionTrue,
515+
Reason: string(gatewayv1.GatewayReasonAccepted),
516+
},
517+
},
518+
},
519+
},
520+
}
495521
},
496522
expectedError: false,
497523
expectedConditions: []metav1.Condition{
@@ -508,11 +534,11 @@ func TestHTTPProxyReconcile(t *testing.T) {
508534
},
509535
assert: func(t *testContext, cl client.Client, httpProxy *networkingv1alpha.HTTPProxy) {
510536
if assert.Len(t, httpProxy.Status.Addresses, 1) {
511-
assert.Equal(t, "test.example.com", httpProxy.Status.Addresses[0].Value)
537+
assert.Equal(t, t.gateway.Status.Addresses[0].Value, httpProxy.Status.Addresses[0].Value)
512538
}
513539

514540
if assert.Len(t, httpProxy.Status.Hostnames, 1) {
515-
assert.Equal(t, gatewayv1.Hostname("test.example.com"), httpProxy.Status.Hostnames[0])
541+
assert.Equal(t, ptr.Deref(t.gateway.Spec.Listeners[0].Hostname, ""), httpProxy.Status.Hostnames[0])
516542
}
517543
},
518544
},
@@ -665,6 +691,15 @@ func TestHTTPProxyReconcile(t *testing.T) {
665691
t.Run(tt.name, func(t *testing.T) {
666692
var initialObjects []client.Object
667693

694+
tt.existingObjects = append(tt.existingObjects, &gatewayv1.GatewayClass{
695+
ObjectMeta: metav1.ObjectMeta{
696+
Name: "test-gateway-class",
697+
},
698+
Spec: gatewayv1.GatewayClassSpec{
699+
ControllerName: testConfig.Gateway.ControllerName,
700+
},
701+
})
702+
668703
for _, obj := range tt.existingObjects {
669704
obj.SetCreationTimestamp(metav1.Now())
670705
}
@@ -676,20 +711,35 @@ func TestHTTPProxyReconcile(t *testing.T) {
676711
WithScheme(testScheme).
677712
WithObjects(initialObjects...).
678713
WithStatusSubresource(initialObjects...).
679-
WithStatusSubresource(&gatewayv1.Gateway{})
680-
681-
if tt.postCreateGatewayStatus != nil {
682-
fakeClientBuilder.WithStatusSubresource(tt.postCreateGatewayStatus)
683-
}
714+
WithStatusSubresource(&gatewayv1.Gateway{}).
715+
WithInterceptorFuncs(interceptor.Funcs{
716+
Create: func(ctx context.Context, client client.WithWatch, obj client.Object, opts ...client.CreateOption) error {
717+
obj.SetUID(uuid.NewUUID())
718+
obj.SetCreationTimestamp(metav1.Now())
719+
return client.Create(ctx, obj, opts...)
720+
},
721+
})
684722

685723
fakeClient := fakeClientBuilder.Build()
724+
725+
fakeDownstreamClient := fake.NewClientBuilder().
726+
WithScheme(testScheme).
727+
WithStatusSubresource(&gatewayv1.Gateway{}).
728+
Build()
729+
686730
mgr := &fakeMockManager{cl: fakeClient}
687731

688732
reconciler := &HTTPProxyReconciler{
689733
mgr: mgr,
690734
Config: testConfig,
691735
}
692736

737+
gatewayReconciler := &GatewayReconciler{
738+
mgr: mgr,
739+
Config: testConfig,
740+
DownstreamCluster: &fakeCluster{cl: fakeDownstreamClient},
741+
}
742+
693743
req := mcreconcile.Request{
694744
Request: reconcile.Request{
695745
NamespacedName: client.ObjectKeyFromObject(tt.httpProxy),
@@ -708,14 +758,16 @@ func TestHTTPProxyReconcile(t *testing.T) {
708758
assert.NoError(t, err)
709759
}
710760

761+
_, err = gatewayReconciler.Reconcile(ctx, req)
762+
assert.NoError(t, err, "unexpected error reconciling gateway")
763+
711764
var updatedProxy networkingv1alpha.HTTPProxy
712765
err = fakeClient.Get(ctx, client.ObjectKeyFromObject(tt.httpProxy), &updatedProxy)
713766
assert.NoError(t, err)
714767

715768
var gateway gatewayv1.Gateway
716769
err = fakeClient.Get(ctx, client.ObjectKeyFromObject(tt.httpProxy), &gateway)
717770
if assert.NoError(t, err) {
718-
719771
apimeta.SetStatusCondition(&gateway.Status.Conditions, metav1.Condition{
720772
Type: string(gatewayv1.GatewayConditionAccepted),
721773
Status: metav1.ConditionTrue,
@@ -727,10 +779,9 @@ func TestHTTPProxyReconcile(t *testing.T) {
727779
if assert.NoError(t, fakeClient.Status().Update(ctx, &gateway), "unexpected error while updating gateway status") {
728780
if tt.postCreateGatewayStatus != nil {
729781

730-
gateway.Status = tt.postCreateGatewayStatus.Status
782+
tt.postCreateGatewayStatus(&gateway)
731783
err = fakeClient.Status().Update(ctx, &gateway)
732784
assert.NoError(t, err)
733-
734785
}
735786

736787
_, err = reconciler.Reconcile(ctx, req)
@@ -751,7 +802,12 @@ func TestHTTPProxyReconcile(t *testing.T) {
751802
}
752803

753804
if tt.assert != nil {
754-
tt.assert(&testContext{T: t, reconciler: reconciler}, fakeClient, &updatedProxy)
805+
testCtx := &testContext{
806+
T: t,
807+
reconciler: reconciler,
808+
gateway: &gateway,
809+
}
810+
tt.assert(testCtx, fakeClient, &updatedProxy)
755811
}
756812

757813
})

0 commit comments

Comments
 (0)