diff --git a/changelogs/unreleased/5961-izturn-small.md b/changelogs/unreleased/5961-izturn-small.md new file mode 100644 index 00000000000..130c664704c --- /dev/null +++ b/changelogs/unreleased/5961-izturn-small.md @@ -0,0 +1 @@ +For Gateway API v1.0, the successful attachment of a Route to a Listener is based solely on the combination of the AllowedRoutes field on the corresponding Listener and the Route's ParentRefs field. diff --git a/internal/dag/gatewayapi_processor.go b/internal/dag/gatewayapi_processor.go index 5a50d6fcf39..b76ef7f07a6 100644 --- a/internal/dag/gatewayapi_processor.go +++ b/internal/dag/gatewayapi_processor.go @@ -138,12 +138,9 @@ func (p *GatewayAPIProcessor) Run(dag *DAG, source *KubernetesCache) { } // Compute listeners and save a list of the valid/ready ones. - var readyListeners []*listenerInfo - + var listenerInfos []*listenerInfo for _, listener := range p.source.gateway.Spec.Listeners { - if ready, listenerInfo := p.computeListener(listener, gwAccessor, validateListenersResult); ready { - readyListeners = append(readyListeners, listenerInfo) - } + listenerInfos = append(listenerInfos, p.computeListener(listener, gwAccessor, validateListenersResult)) } // Keep track of the number of routes attached @@ -152,22 +149,22 @@ func (p *GatewayAPIProcessor) Run(dag *DAG, source *KubernetesCache) { // Process HTTPRoutes. for _, httpRoute := range p.source.httproutes { - p.processRoute(KindHTTPRoute, httpRoute, httpRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, readyListeners, listenerAttachedRoutes, &gatewayapi_v1beta1.HTTPRoute{}) + p.processRoute(KindHTTPRoute, httpRoute, httpRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, listenerInfos, listenerAttachedRoutes, &gatewayapi_v1beta1.HTTPRoute{}) } // Process TLSRoutes. for _, tlsRoute := range p.source.tlsroutes { - p.processRoute(KindTLSRoute, tlsRoute, tlsRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, readyListeners, listenerAttachedRoutes, &gatewayapi_v1alpha2.TLSRoute{}) + p.processRoute(KindTLSRoute, tlsRoute, tlsRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, listenerInfos, listenerAttachedRoutes, &gatewayapi_v1alpha2.TLSRoute{}) } // Process GRPCRoutes. for _, grpcRoute := range p.source.grpcroutes { - p.processRoute(KindGRPCRoute, grpcRoute, grpcRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, readyListeners, listenerAttachedRoutes, &gatewayapi_v1alpha2.GRPCRoute{}) + p.processRoute(KindGRPCRoute, grpcRoute, grpcRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, listenerInfos, listenerAttachedRoutes, &gatewayapi_v1alpha2.GRPCRoute{}) } // Process TCPRoutes. for _, tcpRoute := range p.source.tcproutes { - p.processRoute(KindTCPRoute, tcpRoute, tcpRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, readyListeners, listenerAttachedRoutes, &gatewayapi_v1alpha2.TCPRoute{}) + p.processRoute(KindTCPRoute, tcpRoute, tcpRoute.Spec.ParentRefs, gatewayNotProgrammedCondition, listenerInfos, listenerAttachedRoutes, &gatewayapi_v1alpha2.TCPRoute{}) } for listenerName, attachedRoutes := range listenerAttachedRoutes { @@ -182,7 +179,7 @@ func (p *GatewayAPIProcessor) processRoute( route client.Object, parentRefs []gatewayapi_v1beta1.ParentReference, gatewayNotProgrammedCondition *metav1.Condition, - readyListeners []*listenerInfo, + listeners []*listenerInfo, listenerAttachedRoutes map[string]int, emptyResource client.Object, ) { @@ -200,16 +197,17 @@ func (p *GatewayAPIProcessor) processRoute( } routeParentStatus := routeStatus.StatusUpdateFor(routeParentRef) - // If the Gateway is invalid, set status on the route and we're done. if gatewayNotProgrammedCondition != nil { routeParentStatus.AddCondition(gatewayapi_v1beta1.RouteConditionAccepted, metav1.ConditionFalse, status.ReasonInvalidGateway, "Invalid Gateway") continue } - // Get the list of listeners that are (a) included by this parent ref, and - // (b) allow the route (based on kind, namespace). - allowedListeners := p.getListenersForRouteParentRef(routeParentRef, route.GetNamespace(), routeKind, readyListeners, routeParentStatus) + // Get the list of listeners that are + // (a) included by this parent ref, and + // (b) allow the route (based on kind, namespace), and + // (c) the 'listenerInfo.ready' is true + allowedListeners := p.getListenersForRouteParentRef(routeParentRef, route.GetNamespace(), routeKind, listeners, listenerAttachedRoutes, routeParentStatus) if len(allowedListeners) == 0 { p.resolveRouteRefs(route, routeParentStatus) } @@ -253,21 +251,15 @@ func (p *GatewayAPIProcessor) processRoute( } } - var attached bool - switch route := route.(type) { case *gatewayapi_v1beta1.HTTPRoute: - attached = p.computeHTTPRouteForListener(route, routeParentStatus, listener, hosts) + p.computeHTTPRouteForListener(route, routeParentStatus, listener, hosts) case *gatewayapi_v1alpha2.TLSRoute: - attached = p.computeTLSRouteForListener(route, routeParentStatus, listener, hosts) + p.computeTLSRouteForListener(route, routeParentStatus, listener, hosts) case *gatewayapi_v1alpha2.GRPCRoute: - attached = p.computeGRPCRouteForListener(route, routeParentStatus, listener, hosts) + p.computeGRPCRouteForListener(route, routeParentStatus, listener, hosts) case *gatewayapi_v1alpha2.TCPRoute: - attached = p.computeTCPRouteForListener(route, routeParentStatus, listener) - } - - if attached { - listenerAttachedRoutes[string(listener.listener.Name)]++ + p.computeTCPRouteForListener(route, routeParentStatus, listener) } hostCount += hosts.Len() @@ -309,7 +301,8 @@ func (p *GatewayAPIProcessor) getListenersForRouteParentRef( routeParentRef gatewayapi_v1beta1.ParentReference, routeNamespace string, routeKind gatewayapi_v1beta1.Kind, - validListeners []*listenerInfo, + listeners []*listenerInfo, + attachedRoutes map[string]int, routeParentStatusAccessor *status.RouteParentStatusUpdate, ) []*listenerInfo { @@ -318,30 +311,30 @@ func (p *GatewayAPIProcessor) getListenersForRouteParentRef( // gateway, or one of them, if the ref is to a specific listener, // or none of them, if the listener(s) the ref targets are invalid). var selectedListeners []*listenerInfo - for _, validListener := range validListeners { + for _, listener := range listeners { // We've already verified the parent ref is for this Gateway, // now check if it has a listener name and port specified. // Both need to match the listener if specified. - if (routeParentRef.SectionName == nil || *routeParentRef.SectionName == validListener.listener.Name) && - (routeParentRef.Port == nil || *routeParentRef.Port == validListener.listener.Port) { - selectedListeners = append(selectedListeners, validListener) + if (routeParentRef.SectionName == nil || *routeParentRef.SectionName == listener.listener.Name) && + (routeParentRef.Port == nil || *routeParentRef.Port == listener.listener.Port) { + selectedListeners = append(selectedListeners, listener) } } - if len(selectedListeners) == 0 { - routeParentStatusAccessor.AddCondition( - gatewayapi_v1beta1.RouteConditionAccepted, - metav1.ConditionFalse, - gatewayapi_v1.RouteReasonNoMatchingParent, - "No listeners match this parent ref", - ) - return nil - } - // Now find the subset of those listeners that allow this route // to select them, based on route kind and namespace. var allowedListeners []*listenerInfo + + readyListenerCount := 0 + for _, selectedListener := range selectedListeners { + + // for compute the AttachedRoutes, the listener that not passed its check(s), had been selected too + // so ignore it. + if selectedListener.ready { + readyListenerCount++ + } + // Check if the listener allows routes of this kind if !selectedListener.AllowsKind(routeKind) { continue @@ -352,7 +345,21 @@ func (p *GatewayAPIProcessor) getListenersForRouteParentRef( continue } - allowedListeners = append(allowedListeners, selectedListener) + attachedRoutes[string(selectedListener.listener.Name)]++ + + if selectedListener.ready { + allowedListeners = append(allowedListeners, selectedListener) + } + + } + if readyListenerCount == 0 { + routeParentStatusAccessor.AddCondition( + gatewayapi_v1beta1.RouteConditionAccepted, + metav1.ConditionFalse, + gatewayapi_v1.RouteReasonNoMatchingParent, + "No listeners match this parent ref", + ) + return nil } if len(allowedListeners) == 0 { @@ -374,6 +381,7 @@ type listenerInfo struct { allowedKinds []gatewayapi_v1beta1.Kind namespaceSelector labels.Selector tlsSecret *Secret + ready bool } func (l *listenerInfo) AllowsKind(kind gatewayapi_v1beta1.Kind) bool { @@ -421,7 +429,12 @@ func (p *GatewayAPIProcessor) computeListener( listener gatewayapi_v1beta1.Listener, gwAccessor *status.GatewayStatusUpdate, validateListenersResult gatewayapi.ValidateListenersResult, -) (bool, *listenerInfo) { +) *listenerInfo { + + info := &listenerInfo{ + listener: listener, + dagListenerName: validateListenersResult.ListenerNames[string(listener.Name)], + } addInvalidListenerCondition := func(msg string) { gwAccessor.AddListenerCondition( @@ -509,39 +522,37 @@ func (p *GatewayAPIProcessor) computeListener( } }() - // If the listener had an invalid protocol/port/hostname, we don't need to go - // any further. - if _, ok := validateListenersResult.InvalidListenerConditions[listener.Name]; ok { - return false, nil - } - // Get a list of the route kinds that the listener accepts. - listenerRouteKinds := p.getListenerRouteKinds(listener, gwAccessor) - gwAccessor.SetListenerSupportedKinds(string(listener.Name), listenerRouteKinds) - - var selector labels.Selector + info.allowedKinds = p.getListenerRouteKinds(listener, gwAccessor) + gwAccessor.SetListenerSupportedKinds(string(listener.Name), info.allowedKinds) if listener.AllowedRoutes != nil && listener.AllowedRoutes.Namespaces != nil && listener.AllowedRoutes.Namespaces.From != nil && *listener.AllowedRoutes.Namespaces.From == gatewayapi_v1.NamespacesFromSelector { if listener.AllowedRoutes.Namespaces.Selector == nil { addInvalidListenerCondition("Listener.AllowedRoutes.Namespaces.Selector is required when Listener.AllowedRoutes.Namespaces.From is set to \"Selector\".") - return false, nil + return info } if len(listener.AllowedRoutes.Namespaces.Selector.MatchExpressions)+len(listener.AllowedRoutes.Namespaces.Selector.MatchLabels) == 0 { addInvalidListenerCondition("Listener.AllowedRoutes.Namespaces.Selector must specify at least one MatchLabel or MatchExpression.") - return false, nil + return info } var err error - selector, err = metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) + info.namespaceSelector, err = metav1.LabelSelectorAsSelector(listener.AllowedRoutes.Namespaces.Selector) if err != nil { addInvalidListenerCondition(fmt.Sprintf("Error parsing Listener.AllowedRoutes.Namespaces.Selector: %v.", err)) - return false, nil + return info } } + // If the listener had an invalid protocol/port/hostname, we reach here just for pick the information to compute the AttachedRoutes later, + // we don't need to go any further. + if _, invalid := validateListenersResult.InvalidListenerConditions[listener.Name]; invalid { + return info + } + var listenerSecret *Secret // Validate TLS details for HTTPS/TLS protocol listeners. @@ -553,19 +564,19 @@ func (p *GatewayAPIProcessor) computeListener( if listener.TLS == nil { addInvalidListenerCondition(fmt.Sprintf("Listener.TLS is required when protocol is %q.", listener.Protocol)) - return false, nil + return info } if listener.TLS.Mode != nil && *listener.TLS.Mode != gatewayapi_v1.TLSModeTerminate { addInvalidListenerCondition(fmt.Sprintf("Listener.TLS.Mode must be %q when protocol is %q.", gatewayapi_v1.TLSModeTerminate, listener.Protocol)) - return false, nil + return info } // Resolve the TLS secret. if listenerSecret = p.resolveListenerSecret(listener.TLS.CertificateRefs, string(listener.Name), gwAccessor); listenerSecret == nil { // If TLS was configured on the Listener, but the secret ref is invalid, don't allow any // routes to be bound to this listener since it can't serve TLS traffic. - return false, nil + return info } case gatewayapi_v1.TLSProtocolType: // The TLS protocol is used for TCP traffic encrypted with TLS. @@ -573,7 +584,7 @@ func (p *GatewayAPIProcessor) computeListener( // or passed through to the backend. if listener.TLS == nil { addInvalidListenerCondition(fmt.Sprintf("Listener.TLS is required when protocol is %q.", listener.Protocol)) - return false, nil + return info } switch { @@ -582,26 +593,23 @@ func (p *GatewayAPIProcessor) computeListener( if listenerSecret = p.resolveListenerSecret(listener.TLS.CertificateRefs, string(listener.Name), gwAccessor); listenerSecret == nil { // If TLS was configured on the Listener, but the secret ref is invalid, don't allow any // routes to be bound to this listener since it can't serve TLS traffic. - return false, nil + return info } case *listener.TLS.Mode == gatewayapi_v1.TLSModePassthrough: if len(listener.TLS.CertificateRefs) != 0 { addInvalidListenerCondition(fmt.Sprintf("Listener.TLS.CertificateRefs cannot be defined when Listener.TLS.Mode is %q.", gatewayapi_v1.TLSModePassthrough)) - return false, nil + return info } default: addInvalidListenerCondition(fmt.Sprintf("Listener.TLS.Mode must be %q or %q.", gatewayapi_v1.TLSModeTerminate, gatewayapi_v1.TLSModePassthrough)) - return false, nil + return info } } - return true, &listenerInfo{ - listener: listener, - dagListenerName: validateListenersResult.ListenerNames[string(listener.Name)], - allowedKinds: listenerRouteKinds, - tlsSecret: listenerSecret, - namespaceSelector: selector, - } + info.tlsSecret = listenerSecret + info.ready = true + return info + } // getListenerRouteKinds gets a list of the valid route kinds that @@ -1130,15 +1138,18 @@ func parseHTTPRouteTimeouts(httpRouteTimeouts *gatewayapi_v1.HTTPRouteTimeouts) ResponseTimeout: requestTimeout, }, nil } +func (p *GatewayAPIProcessor) computeHTTPRouteForListener( + route *gatewayapi_v1beta1.HTTPRoute, + routeAccessor *status.RouteParentStatusUpdate, + listener *listenerInfo, + hosts sets.Set[string]) { -func (p *GatewayAPIProcessor) computeHTTPRouteForListener(route *gatewayapi_v1beta1.HTTPRoute, routeAccessor *status.RouteParentStatusUpdate, listener *listenerInfo, hosts sets.Set[string]) bool { - var programmed bool for ruleIndex, rule := range route.Spec.Rules { // Get match conditions for the rule. var matchconditions []*matchConditions for _, match := range rule.Matches { - pathMatch, ok := gatewayPathMatchCondition(match.Path, routeAccessor) - if !ok { + pathMatch := gatewayPathMatchCondition(match.Path, routeAccessor) + if pathMatch == nil { continue } @@ -1421,13 +1432,9 @@ func (p *GatewayAPIProcessor) computeHTTPRouteForListener(route *gatewayapi_v1be vhost := p.dag.EnsureVirtualHost(listener.dagListenerName, host) vhost.AddRoute(route) } - - programmed = true } } } - - return programmed } func (p *GatewayAPIProcessor) computeGRPCRouteForListener(route *gatewayapi_v1alpha2.GRPCRoute, routeAccessor *status.RouteParentStatusUpdate, listener *listenerInfo, hosts sets.Set[string]) bool { @@ -1820,9 +1827,9 @@ func validateAppProtocol(svc *v1.ServicePort) error { return fmt.Errorf("AppProtocol: \"%s\" is unsupported", *svc.AppProtocol) } -func gatewayPathMatchCondition(match *gatewayapi_v1beta1.HTTPPathMatch, routeAccessor *status.RouteParentStatusUpdate) (MatchCondition, bool) { +func gatewayPathMatchCondition(match *gatewayapi_v1beta1.HTTPPathMatch, routeAccessor *status.RouteParentStatusUpdate) MatchCondition { if match == nil { - return &PrefixMatchCondition{Prefix: "/"}, true + return &PrefixMatchCondition{Prefix: "/"} } path := ref.Val(match.Value, "/") @@ -1831,41 +1838,40 @@ func gatewayPathMatchCondition(match *gatewayapi_v1beta1.HTTPPathMatch, routeAcc if match.Type == nil || *match.Type == gatewayapi_v1.PathMatchPathPrefix { if !strings.HasPrefix(path, "/") { routeAccessor.AddCondition(status.ConditionValidMatches, metav1.ConditionFalse, status.ReasonInvalidPathMatch, "Match.Path.Value must start with '/'.") - return nil, false + return nil } if strings.Contains(path, "//") { routeAccessor.AddCondition(status.ConditionValidMatches, metav1.ConditionFalse, status.ReasonInvalidPathMatch, "Match.Path.Value must not contain consecutive '/' characters.") - return nil, false + return nil } // As an optimization, if path is just "/", we can use // string prefix matching instead of segment prefix // matching which requires a regex. if path == "/" { - return &PrefixMatchCondition{Prefix: path}, true + return &PrefixMatchCondition{Prefix: path} } - return &PrefixMatchCondition{Prefix: path, PrefixMatchType: PrefixMatchSegment}, true + return &PrefixMatchCondition{Prefix: path, PrefixMatchType: PrefixMatchSegment} } if *match.Type == gatewayapi_v1.PathMatchExact { if !strings.HasPrefix(path, "/") { routeAccessor.AddCondition(status.ConditionValidMatches, metav1.ConditionFalse, status.ReasonInvalidPathMatch, "Match.Path.Value must start with '/'.") - return nil, false + return nil } if strings.Contains(path, "//") { routeAccessor.AddCondition(status.ConditionValidMatches, metav1.ConditionFalse, status.ReasonInvalidPathMatch, "Match.Path.Value must not contain consecutive '/' characters.") - return nil, false + return nil } - - return &ExactMatchCondition{Path: path}, true + return &ExactMatchCondition{Path: path} } if *match.Type == gatewayapi_v1.PathMatchRegularExpression { if err := ValidateRegex(*match.Value); err != nil { routeAccessor.AddCondition(status.ConditionValidMatches, metav1.ConditionFalse, status.ReasonInvalidPathMatch, "Match.Path.Value is invalid for RegularExpression match type.") - return nil, false + return nil } - return &RegexMatchCondition{Regex: path}, true + return &RegexMatchCondition{Regex: path} } routeAccessor.AddCondition( @@ -1874,7 +1880,7 @@ func gatewayPathMatchCondition(match *gatewayapi_v1beta1.HTTPPathMatch, routeAcc gatewayapi_v1beta1.RouteReasonUnsupportedValue, "HTTPRoute.Spec.Rules.PathMatch: Only Prefix match type, Exact match type and RegularExpression match type are supported.", ) - return nil, false + return nil } func gatewayHeaderMatchConditions(matches []gatewayapi_v1beta1.HTTPHeaderMatch) ([]HeaderMatchCondition, error) { diff --git a/internal/dag/gatewayapi_processor_test.go b/internal/dag/gatewayapi_processor_test.go index bfec5ba9950..a1cd47da0cb 100644 --- a/internal/dag/gatewayapi_processor_test.go +++ b/internal/dag/gatewayapi_processor_test.go @@ -466,6 +466,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, { listener: gatewayapi_v1beta1.Listener{ @@ -477,6 +478,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, }, want: []int{0, 1}, @@ -526,6 +528,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, { listener: gatewayapi_v1beta1.Listener{ @@ -537,6 +540,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, }, want: []int{0, 1}, @@ -587,6 +591,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, { listener: gatewayapi_v1beta1.Listener{ @@ -598,6 +603,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, }, want: []int{0}, @@ -617,6 +623,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, { listener: gatewayapi_v1beta1.Listener{ @@ -628,6 +635,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, }, want: []int{1}, @@ -677,6 +685,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"TLSRoute"}, + ready: true, }, { listener: gatewayapi_v1beta1.Listener{ @@ -688,6 +697,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, }, want: []int{1}, @@ -707,6 +717,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"GRPCRoute"}, + ready: true, }, { listener: gatewayapi_v1beta1.Listener{ @@ -718,6 +729,7 @@ func TestGetListenersForRouteParentRef(t *testing.T) { }, }, allowedKinds: []gatewayapi_v1beta1.Kind{"HTTPRoute"}, + ready: true, }, }, want: []int{0}, @@ -742,7 +754,13 @@ func TestGetListenersForRouteParentRef(t *testing.T) { rsu := &status.RouteStatusUpdate{} rpsu := rsu.StatusUpdateFor(tc.routeParentRef) - got := processor.getListenersForRouteParentRef(tc.routeParentRef, tc.routeNamespace, gatewayapi_v1beta1.Kind(tc.routeKind), tc.listeners, rpsu) + got := processor.getListenersForRouteParentRef( + tc.routeParentRef, + tc.routeNamespace, + gatewayapi_v1beta1.Kind(tc.routeKind), + tc.listeners, + map[string]int{}, + rpsu) var want []*listenerInfo for _, i := range tc.want { diff --git a/internal/dag/status_test.go b/internal/dag/status_test.go index 5ba73a1cef5..659da1a04cb 100644 --- a/internal/dag/status_test.go +++ b/internal/dag/status_test.go @@ -5218,6 +5218,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { for _, o := range tc.objs { builder.Source.Insert(o) } + dag := builder.Build() gotRouteUpdates := dag.StatusCache.GetRouteUpdates() gotGatewayUpdates := dag.StatusCache.GetGatewayUpdates() @@ -5506,7 +5507,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "exact path match not starting with '/' for httproute", testcase{ objs: []any{ @@ -5552,7 +5553,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "regular expression path match with invalid value for httproute", testcase{ @@ -5594,7 +5595,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "prefix path match with consecutive '/' characters for httproute", testcase{ @@ -5641,7 +5642,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "exact path match with consecutive '/' characters for httproute", testcase{ @@ -5688,7 +5689,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "invalid path match type for httproute", testcase{ @@ -5729,7 +5730,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "invalid header match type not supported for httproute", testcase{ @@ -5777,7 +5778,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "regular expression header match with invalid value for httproute", testcase{ @@ -5825,7 +5826,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "regular expression query param match with valid value for httproute", testcase{ @@ -5926,7 +5927,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "query param match with invalid type for httproute", testcase{ @@ -5974,7 +5975,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "spec.rules.backendRef.name not specified", testcase{ @@ -6150,7 +6151,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "spec.rules.backendRef.namespace does not match route", testcase{ @@ -6917,7 +6918,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "spec.rules.hostname: invalid hostname", testcase{ @@ -6959,7 +6960,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "spec.rules.hostname: invalid hostname, ip address", testcase{ @@ -6999,7 +7000,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "two HTTP listeners, route's hostname intersects with one of them", testcase{ @@ -7095,7 +7096,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, "listener-2": { Name: gatewayapi_v1beta1.SectionName("listener-2"), - AttachedRoutes: int32(0), + AttachedRoutes: int32(1), SupportedKinds: []gatewayapi_v1beta1.RouteGroupKind{ { Group: ref.To(gatewayapi_v1beta1.Group(gatewayapi_v1beta1.GroupName)), @@ -7196,7 +7197,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { ListenerStatus: map[string]*gatewayapi_v1beta1.ListenerStatus{ "listener-1": { Name: gatewayapi_v1beta1.SectionName("listener-1"), - AttachedRoutes: int32(0), + AttachedRoutes: int32(1), SupportedKinds: []gatewayapi_v1beta1.RouteGroupKind{ { Group: ref.To(gatewayapi_v1beta1.Group(gatewayapi_v1beta1.GroupName)), @@ -7211,7 +7212,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, "listener-2": { Name: gatewayapi_v1beta1.SectionName("listener-2"), - AttachedRoutes: int32(0), + AttachedRoutes: int32(1), SupportedKinds: []gatewayapi_v1beta1.RouteGroupKind{ { Group: ref.To(gatewayapi_v1beta1.Group(gatewayapi_v1beta1.GroupName)), @@ -9222,6 +9223,100 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) + run(t, "HTTP listener with invalid AllowedRoute kind referenced by route parent ref", testcase{ + objs: []any{ + kuardService, + &gatewayapi_v1beta1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: "basic", + Namespace: "default", + }, + Spec: gatewayapi_v1beta1.HTTPRouteSpec{ + CommonRouteSpec: gatewayapi_v1beta1.CommonRouteSpec{ + ParentRefs: []gatewayapi_v1beta1.ParentReference{gatewayapi.GatewayListenerParentRef("projectcontour", "contour", "listener-1", 80)}, + }, + Hostnames: []gatewayapi_v1beta1.Hostname{"foo.projectcontour.io"}, + Rules: []gatewayapi_v1beta1.HTTPRouteRule{{ + Matches: gatewayapi.HTTPRouteMatch(gatewayapi_v1.PathMatchPathPrefix, "/"), + BackendRefs: gatewayapi.HTTPBackendRef("kuard", 8080, 1), + }}, + }, + }}, + gateway: &gatewayapi_v1beta1.Gateway{ + ObjectMeta: metav1.ObjectMeta{ + Name: "contour", + Namespace: "projectcontour", + }, + Spec: gatewayapi_v1beta1.GatewaySpec{ + Listeners: []gatewayapi_v1beta1.Listener{ + { + Name: "listener-1", + Port: 80, + Protocol: gatewayapi_v1.HTTPProtocolType, + AllowedRoutes: &gatewayapi_v1beta1.AllowedRoutes{ + Kinds: []gatewayapi_v1beta1.RouteGroupKind{ + {Kind: "FooRoute"}, + }, + }, + Hostname: ref.To(gatewayapi_v1beta1.Hostname("*.projectcontour.io")), + }, + }, + }, + }, + wantRouteConditions: []*status.RouteStatusUpdate{{ + FullName: types.NamespacedName{Namespace: "default", Name: "basic"}, + RouteParentStatuses: []*gatewayapi_v1beta1.RouteParentStatus{ + { + ParentRef: gatewayapi.GatewayListenerParentRef("projectcontour", "contour", "listener-1", 80), + Conditions: []metav1.Condition{ + { + Type: string(gatewayapi_v1.RouteConditionAccepted), + Status: contour_api_v1.ConditionFalse, + Reason: string(gatewayapi_v1beta1.RouteReasonNotAllowedByListeners), + Message: "No listeners included by this parent ref allowed this attachment.", + }, + routeResolvedRefsCondition(), + }, + }, + }, + }}, + wantGatewayStatusUpdate: []*status.GatewayStatusUpdate{ + { + FullName: types.NamespacedName{Namespace: "projectcontour", Name: "contour"}, + Conditions: map[gatewayapi_v1.GatewayConditionType]metav1.Condition{ + gatewayapi_v1.GatewayConditionAccepted: gatewayAcceptedCondition(), + gatewayapi_v1.GatewayConditionProgrammed: { + Type: string(gatewayapi_v1.GatewayConditionProgrammed), + Status: contour_api_v1.ConditionFalse, + Reason: string(gatewayapi_v1.GatewayReasonListenersNotValid), + Message: "Listeners are not valid", + }, + }, + ListenerStatus: map[string]*gatewayapi_v1beta1.ListenerStatus{ + "listener-1": { + Name: gatewayapi_v1beta1.SectionName("listener-1"), + AttachedRoutes: int32(0), + Conditions: []metav1.Condition{ + { + Type: string(gatewayapi_v1.ListenerConditionResolvedRefs), + Status: metav1.ConditionFalse, + Reason: string(gatewayapi_v1.ListenerReasonInvalidRouteKinds), + Message: "Kind \"FooRoute\" is not supported, kind must be \"HTTPRoute\", \"TLSRoute\", \"GRPCRoute\" or \"TCPRoute\"", + }, + { + Type: string(gatewayapi_v1.ListenerConditionProgrammed), + Status: metav1.ConditionFalse, + Reason: string(gatewayapi_v1.ListenerReasonInvalid), + Message: "Invalid listener, see other listener conditions for details", + }, + listenerAcceptedCondition(), + }, + }, + }, + }, + }, + }) + run(t, "route rule with timeouts.request and timeouts.backendRequest specified", testcase{ objs: []any{ kuardService, @@ -9249,10 +9344,12 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, + wantRouteConditions: []*status.RouteStatusUpdate{{ FullName: types.NamespacedName{Namespace: "default", Name: "basic"}, RouteParentStatuses: []*gatewayapi_v1beta1.RouteParentStatus{ { + ParentRef: gatewayapi.GatewayParentRef("projectcontour", "contour"), Conditions: []metav1.Condition{ routeResolvedRefsCondition(), @@ -9261,7 +9358,8 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "route rule with only timeouts.backendRequest specified", testcase{ @@ -9302,7 +9400,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "timeouts with invalid request for httproute", testcase{ @@ -9340,7 +9438,7 @@ func TestGatewayAPIHTTPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) } @@ -9516,7 +9614,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: spec.rules.backendRef.name invalid on two matches", testcase{ @@ -9559,7 +9657,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: spec.rules.backendRef.port not specified", testcase{ @@ -9607,7 +9705,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: spec.rules.backendRefs not specified", testcase{ @@ -9648,7 +9746,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: spec.rules.hostname: invalid wildcard", testcase{ @@ -9691,7 +9789,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: spec.rules.hostname: invalid hostname", testcase{ @@ -9734,7 +9832,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: spec.rules.hostname: invalid hostname, ip address", testcase{ @@ -9775,7 +9873,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: spec.rules.backendRefs has 0 weight", testcase{ @@ -9822,7 +9920,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate(string(gw.Spec.Listeners[0].Name), gw.Spec.Listeners[0].Protocol, 1), }) run(t, "TLSRoute: backendrefs still validated when route not accepted", testcase{ @@ -9964,6 +10062,7 @@ func TestGatewayAPITLSRouteDAGStatus(t *testing.T) { listenerAcceptedCondition(), listenerResolvedRefsCondition(), }, + AttachedRoutes: 1, }, }, }}, @@ -10193,7 +10292,7 @@ func TestGatewayAPIGRPCRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "grpcroute: method match must have Service configured", testcase{ @@ -10236,7 +10335,7 @@ func TestGatewayAPIGRPCRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "grpcroute: method match must have Method configured", testcase{ @@ -10279,7 +10378,7 @@ func TestGatewayAPIGRPCRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "grpcroute: invalid header match type is not supported", testcase{ @@ -10334,7 +10433,7 @@ func TestGatewayAPIGRPCRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "grpcroute: regular expression header match has invalid value", testcase{ @@ -10389,7 +10488,7 @@ func TestGatewayAPIGRPCRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "grpcroute: invalid RequestHeaderModifier due to duplicated headers", testcase{ @@ -10677,7 +10776,7 @@ func TestGatewayAPIGRPCRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("http", gatewayapi_v1.HTTPProtocolType, 1), }) run(t, "grpcroute: still validate backendrefs when not accepted", testcase{ @@ -11076,7 +11175,7 @@ func TestGatewayAPITCPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("tcp", gatewayapi_v1.TCPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("tcp", gatewayapi_v1.TCPProtocolType, 1), }) run(t, "TCPRoute with rule with no backends", testcase{ objs: []any{ @@ -11107,7 +11206,7 @@ func TestGatewayAPITCPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("tcp", gatewayapi_v1.TCPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("tcp", gatewayapi_v1.TCPProtocolType, 1), }) run(t, "TCPRoute with rule with ref to nonexistent backend", testcase{ objs: []any{ @@ -11140,7 +11239,7 @@ func TestGatewayAPITCPRouteDAGStatus(t *testing.T) { }, }, }}, - wantGatewayStatusUpdate: validGatewayStatusUpdate("tcp", gatewayapi_v1.TCPProtocolType, 0), + wantGatewayStatusUpdate: validGatewayStatusUpdate("tcp", gatewayapi_v1.TCPProtocolType, 1), }) } diff --git a/internal/gatewayapi/listeners.go b/internal/gatewayapi/listeners.go index 54194264747..26077c1be9c 100644 --- a/internal/gatewayapi/listeners.go +++ b/internal/gatewayapi/listeners.go @@ -54,6 +54,15 @@ type ListenerPort struct { Protocol string } +func conflictedCondition(reason gatewayapi_v1.ListenerConditionReason, msg string) metav1.Condition { + return metav1.Condition{ + Type: string(gatewayapi_v1.ListenerConditionConflicted), + Status: metav1.ConditionTrue, + Reason: string(reason), + Message: msg, + } +} + // ValidateListeners validates protocols, ports and hostnames on a set of listeners. // It ensures that: // - protocols are supported @@ -134,44 +143,24 @@ func ValidateListeners(listeners []gatewayapi_v1beta1.Listener) ValidateListener switch { case listener.Protocol == gatewayapi_v1.HTTPProtocolType: if otherListener.Protocol != gatewayapi_v1.HTTPProtocolType { - result.InvalidListenerConditions[listener.Name] = metav1.Condition{ - Type: string(gatewayapi_v1.ListenerConditionConflicted), - Status: metav1.ConditionTrue, - Reason: string(gatewayapi_v1.ListenerReasonProtocolConflict), - Message: "All Listener protocols for a given port must be compatible", - } + result.InvalidListenerConditions[listener.Name] = conflictedCondition(gatewayapi_v1.ListenerReasonProtocolConflict, "All Listener protocols for a given port must be compatible") return true } case compatibleTLSProtocols.Has(listener.Protocol): if !compatibleTLSProtocols.Has(otherListener.Protocol) { - result.InvalidListenerConditions[listener.Name] = metav1.Condition{ - Type: string(gatewayapi_v1.ListenerConditionConflicted), - Status: metav1.ConditionTrue, - Reason: string(gatewayapi_v1.ListenerReasonProtocolConflict), - Message: "All Listener protocols for a given port must be compatible", - } + result.InvalidListenerConditions[listener.Name] = conflictedCondition(gatewayapi_v1.ListenerReasonProtocolConflict, "All Listener protocols for a given port must be compatible") return true } case listener.Protocol == gatewayapi_v1.TCPProtocolType: if otherListener.Protocol != gatewayapi_v1.TCPProtocolType { - result.InvalidListenerConditions[listener.Name] = metav1.Condition{ - Type: string(gatewayapi_v1.ListenerConditionConflicted), - Status: metav1.ConditionTrue, - Reason: string(gatewayapi_v1.ListenerReasonProtocolConflict), - Message: "All Listener protocols for a given port must be compatible", - } + result.InvalidListenerConditions[listener.Name] = conflictedCondition(gatewayapi_v1.ListenerReasonProtocolConflict, "All Listener protocols for a given port must be compatible") return true } } // Hostname conflict if ref.Val(listener.Hostname, "") == ref.Val(otherListener.Hostname, "") { - result.InvalidListenerConditions[listener.Name] = metav1.Condition{ - Type: string(gatewayapi_v1.ListenerConditionConflicted), - Status: metav1.ConditionTrue, - Reason: string(gatewayapi_v1.ListenerReasonHostnameConflict), - Message: "All Listener hostnames for a given port must be unique", - } + result.InvalidListenerConditions[listener.Name] = conflictedCondition(gatewayapi_v1.ListenerReasonHostnameConflict, "All Listener hostnames for a given port must be unique") return true } } diff --git a/test/conformance/gatewayapi/gateway_conformance_test.go b/test/conformance/gatewayapi/gateway_conformance_test.go index 3a36f43379d..68e9caf9e70 100644 --- a/test/conformance/gatewayapi/gateway_conformance_test.go +++ b/test/conformance/gatewayapi/gateway_conformance_test.go @@ -76,7 +76,6 @@ func TestGatewayConformance(t *testing.T) { // Tests newly failing with Gateway API 1.0, to be addressed. tests.HTTPRouteTimeoutBackendRequest.ShortName, - tests.GatewayWithAttachedRoutes.ShortName, tests.GatewayStaticAddresses.ShortName, }, ExemptFeatures: sets.New(