diff --git a/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml b/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml index c46b85e132..4749934fd2 100644 --- a/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml +++ b/internal/cmd/egctl/testdata/translate/out/rejected-http-route.route.yaml @@ -78,7 +78,8 @@ httpRoutes: status: "False" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway-system/backend not found + message: 'Failed to process route rule 0 backendRef 0: service envoy-gateway-system/backend + not found.' reason: BackendNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/backend.go b/internal/gatewayapi/backend.go index 6b9bb09571..ae184ee70e 100644 --- a/internal/gatewayapi/backend.go +++ b/internal/gatewayapi/backend.go @@ -39,27 +39,42 @@ func (t *Translator) ProcessBackends(backends []*egv1a1.Backend) []*egv1a1.Backe return res } -func validateBackend(backend *egv1a1.Backend) error { +func validateBackend(backend *egv1a1.Backend) status.Error { for _, ep := range backend.Spec.Endpoints { if ep.FQDN != nil { hostname := ep.FQDN.Hostname // must be a valid hostname if errs := validation.IsDNS1123Subdomain(hostname); errs != nil { - return fmt.Errorf("hostname %s is not a valid FQDN", hostname) + return status.NewRouteStatusError( + fmt.Errorf("hostname %s is not a valid FQDN", hostname), + status.RouteReasonInvalidAddress, + ) } if len(strings.Split(hostname, ".")) < 2 { - return fmt.Errorf("hostname %s should be a domain with at least two segments separated by dots", hostname) + return status.NewRouteStatusError( + fmt.Errorf("hostname %s should be a domain with at least two segments separated by dots", hostname), + status.RouteReasonInvalidAddress, + ) } // IP addresses are not allowed so parsing the hostname as an address needs to fail if _, err := netip.ParseAddr(hostname); err == nil { - return fmt.Errorf("hostname %s is an IP address", hostname) + return status.NewRouteStatusError( + fmt.Errorf("hostname %s is an IP address", hostname), + status.RouteReasonInvalidAddress, + ) } } else if ep.IP != nil { ip, err := netip.ParseAddr(ep.IP.Address) if err != nil { - return fmt.Errorf("IP address %s is invalid", ep.IP.Address) + return status.NewRouteStatusError( + fmt.Errorf("IP address %s is invalid", ep.IP.Address), + status.RouteReasonInvalidAddress, + ) } else if ip.IsLoopback() { - return fmt.Errorf("IP address %s in the loopback range is not supported", ep.IP.Address) + return status.NewRouteStatusError( + fmt.Errorf("IP address %s in the loopback range is not supported", ep.IP.Address), + status.RouteReasonInvalidAddress, + ) } } } diff --git a/internal/gatewayapi/filters.go b/internal/gatewayapi/filters.go index b4ee0ad0bc..97c12bf35d 100644 --- a/internal/gatewayapi/filters.go +++ b/internal/gatewayapi/filters.go @@ -32,7 +32,7 @@ type HTTPFiltersTranslator interface { processRedirectFilter(redirect *gwapiv1.HTTPRequestRedirectFilter, filterContext *HTTPFiltersContext) processRequestHeaderModifierFilter(headerModifier *gwapiv1.HTTPHeaderFilter, filterContext *HTTPFiltersContext) processResponseHeaderModifierFilter(headerModifier *gwapiv1.HTTPHeaderFilter, filterContext *HTTPFiltersContext) - processRequestMirrorFilter(filterIdx int, mirror *gwapiv1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *resource.Resources) error + processRequestMirrorFilter(filterIdx int, mirror *gwapiv1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *resource.Resources) status.Error processUnsupportedHTTPFilter(filterType string, filterContext *HTTPFiltersContext) } @@ -72,14 +72,14 @@ func (t *Translator) ProcessHTTPFilters(parentRef *RouteParentContext, filters []gwapiv1.HTTPRouteFilter, ruleIdx int, resources *resource.Resources, -) (*HTTPFiltersContext, error) { +) (*HTTPFiltersContext, status.Error) { httpFiltersContext := &HTTPFiltersContext{ ParentRef: parentRef, Route: route, RuleIdx: ruleIdx, HTTPFilterIR: &HTTPFilterIR{}, } - var err error + var err status.Error for i := range filters { filter := filters[i] // If an invalid filter type has been configured then skip processing any more filters @@ -881,7 +881,7 @@ func (t *Translator) processRequestMirrorFilter( mirrorFilter *gwapiv1.HTTPRequestMirrorFilter, filterContext *HTTPFiltersContext, resources *resource.Resources, -) error { +) (err status.Error) { // Make sure the config actually exists if mirrorFilter == nil { return nil @@ -901,10 +901,11 @@ func (t *Translator) processRequestMirrorFilter( // This sets the status on the HTTPRoute, should the usage be changed so that the status message reflects that the backendRef is from the filter? filterNs := filterContext.Route.GetNamespace() serviceNamespace := NamespaceDerefOr(mirrorBackend.Namespace, filterNs) - err := t.validateBackendRef(mirrorBackendRef, filterContext.ParentRef, filterContext.Route, + err = t.validateBackendRef(mirrorBackendRef, filterContext.ParentRef, filterContext.Route, resources, serviceNamespace, resource.KindHTTPRoute) if err != nil { - return err + return status.NewRouteStatusError( + fmt.Errorf("failed to validate the RequestMirror filter: %w", err), err.Reason()) } destName := fmt.Sprintf("%s-mirror-%d", irRouteDestinationName(filterContext.Route, filterContext.RuleIdx), filterIdx) diff --git a/internal/gatewayapi/listener.go b/internal/gatewayapi/listener.go index 6633a0c44b..d14e61b52d 100644 --- a/internal/gatewayapi/listener.go +++ b/internal/gatewayapi/listener.go @@ -565,13 +565,13 @@ func (t *Translator) processBackendRefs(name string, backendCluster egv1a1.Backe kind := KindDerefOr(ref.Kind, resource.KindService) switch kind { case resource.KindService: - if _, err := validateBackendRefService(ref.BackendObjectReference, resources, ns, corev1.ProtocolTCP); err != nil { + if err := validateBackendRefService(ref.BackendObjectReference, resources, ns, corev1.ProtocolTCP); err != nil { return nil, nil, err } ds := t.processServiceDestinationSetting(name, ref.BackendObjectReference, ns, ir.TCP, resources, envoyProxy) result = append(result, ds) case resource.KindBackend: - if _, err := t.validateBackendRefBackend(ref.BackendObjectReference, resources, ns, true); err != nil { + if err := t.validateBackendRefBackend(ref.BackendObjectReference, resources, ns, true); err != nil { return nil, nil, err } ds := t.processBackendDestinationSetting(name, ref.BackendObjectReference, ns, ir.TCP, resources) diff --git a/internal/gatewayapi/route.go b/internal/gatewayapi/route.go index da70aa56a1..ee75ac8003 100644 --- a/internal/gatewayapi/route.go +++ b/internal/gatewayapi/route.go @@ -120,17 +120,18 @@ func (t *Translator) processHTTPRouteParentRefs(httpRoute *HTTPRouteContext, res // any conditions that come out of it have to go on each RouteParentStatus, // not on the Route as a whole. routeRoutes, err := t.processHTTPRouteRules(httpRoute, parentRef, resources) + // TODO: zhaohuabing: according to the gateway api, the RouteConditionPartiallyInvalid condition should be set + // to true when an HTTPRoute contains a combination of both valid and invalid rules. if err != nil { routeStatus := GetRouteStatus(httpRoute) status.SetRouteStatusCondition(routeStatus, parentRef.routeParentStatusIdx, httpRoute.GetGeneration(), - gwapiv1.RouteConditionAccepted, + err.Type(), metav1.ConditionFalse, - gwapiv1.RouteReasonUnsupportedValue, // TODO: better reason + err.Reason(), status.Error2ConditionMsg(err), ) - continue } // If no negative condition has been set for ResolvedRefs, set "ResolvedRefs=True" @@ -181,96 +182,117 @@ func (t *Translator) processHTTPRouteParentRefs(httpRoute *HTTPRouteContext, res } } -func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRef *RouteParentContext, resources *resource.Resources) ([]*ir.HTTPRoute, error) { - var routeRoutes []*ir.HTTPRoute - var envoyProxy *egv1a1.EnvoyProxy +func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRef *RouteParentContext, resources *resource.Resources) ([]*ir.HTTPRoute, status.Error) { + var ( + irRoutes []*ir.HTTPRoute + envoyProxy *egv1a1.EnvoyProxy + errs = &status.MultiStatusError{} + ) gatewayCtx := httpRoute.ParentRefs[*parentRef.ParentReference].GetGateway() if gatewayCtx != nil { envoyProxy = gatewayCtx.envoyProxy } - // compute matches, filters, backends + // process each HTTPRouteRule, generate a unique Xds IR HTTPRoute per match of the rule for ruleIdx, rule := range httpRoute.Spec.Rules { httpFiltersContext, err := t.ProcessHTTPFilters(parentRef, httpRoute, rule.Filters, ruleIdx, resources) if err != nil { - return nil, err + errs.Add(status.NewRouteStatusError( + fmt.Errorf("failed to process route rule %d: %w", ruleIdx, err), + status.ConvertToAcceptedReason(err.Reason()), + ).WithType(gwapiv1.RouteConditionAccepted)) + continue } - // A rule is matched if any one of its matches - // is satisfied (i.e. a logical "OR"), so generate - // a unique Xds IR HTTPRoute per match. + + // The HTTPRouteRule matches are ORed, a rule is matched if any one of its matches is satisfied, + // so generate a unique Xds IR HTTPRoute per match. ruleRoutes, err := t.processHTTPRouteRule(httpRoute, ruleIdx, httpFiltersContext, rule) if err != nil { - return nil, err + errs.Add(status.NewRouteStatusError( + fmt.Errorf("failed to process route rule %d: %w", ruleIdx, err), + status.ConvertToAcceptedReason(err.Reason()), + ).WithType(gwapiv1.RouteConditionAccepted)) + continue } dstAddrTypeSet := make(sets.Set[ir.DestinationAddressType]) destName := irRouteDestinationName(httpRoute, ruleIdx) + allDs := []*ir.DestinationSetting{} + failedProcessDestination := false + + // process each backendRef, and calculate the destination settings for this rule for i, backendRef := range rule.BackendRefs { settingName := irDestinationSettingName(destName, i) ds, err := t.processDestination(settingName, backendRef, parentRef, httpRoute, resources) - if !t.IsEnvoyServiceRouting(envoyProxy) && ds != nil && len(ds.Endpoints) > 0 && ds.AddressType != nil { + if err != nil { + errs.Add(status.NewRouteStatusError( + fmt.Errorf("failed to process route rule %d backendRef %d: %w", ruleIdx, i, err), + err.Reason(), + )) + failedProcessDestination = true + continue + } + + // ds can be nil if the backendRef weight is 0 + if ds == nil { + continue + } + allDs = append(allDs, ds) + + if !t.IsEnvoyServiceRouting(envoyProxy) && len(ds.Endpoints) > 0 && ds.AddressType != nil { dstAddrTypeSet.Insert(*ds.AddressType) } + } - for _, route := range ruleRoutes { - // disable associated routes to a backend ref in case some of its config was invalid - if err != nil { - route.DirectResponse = &ir.CustomResponse{ - StatusCode: ptr.To(uint32(500)), - } - continue - } + // process each ir route + for _, irRoute := range ruleRoutes { + destination := &ir.RouteDestination{ + Settings: allDs, + } - if ds == nil { - continue - } - // If the route already has a direct response or redirect configured, then it was from a filter so skip - // processing any destinations for this route. - if route.DirectResponse != nil || route.Redirect != nil { - continue + switch { + // If the route already has a direct response or redirect configured, then it was from a filter so skip + // processing any destinations for this route. + case irRoute.DirectResponse != nil || irRoute.Redirect != nil: + // return 500 if any destination setting is invalid + // the error is already added to the error list when processing the destination + case failedProcessDestination: + irRoute.DirectResponse = &ir.CustomResponse{ + StatusCode: ptr.To(uint32(500)), } - - if route.Destination == nil { - route.Destination = &ir.RouteDestination{ - Name: destName, - } + // return 500 if the weight of all the valid destination settings(endpoints list is not empty) is 0 + case destination.ToBackendWeights().Valid == 0: + irRoute.DirectResponse = &ir.CustomResponse{ + StatusCode: ptr.To(uint32(500)), } - route.Destination.Settings = append(route.Destination.Settings, ds) + default: + destination.Name = destName + destination.Settings = allDs + irRoute.Destination = destination } } // TODO: support mixed endpointslice address type between backendRefs if !t.IsEnvoyServiceRouting(envoyProxy) && (dstAddrTypeSet.Len() > 1 || dstAddrTypeSet.Has(ir.MIXED)) { - routeStatus := GetRouteStatus(httpRoute) - status.SetRouteStatusCondition(routeStatus, - parentRef.routeParentStatusIdx, - httpRoute.GetGeneration(), - gwapiv1.RouteConditionResolvedRefs, - metav1.ConditionFalse, - gwapiv1.RouteReasonResolvedRefs, - "Mixed endpointslice address type between backendRefs is not supported") - } - - // If the route has no valid backends then just use a direct response and don't fuss with weighted responses - for _, ruleRoute := range ruleRoutes { - noValidBackends := ruleRoute.Destination == nil || ruleRoute.Destination.ToBackendWeights().Valid == 0 - if ruleRoute.DirectResponse == nil && noValidBackends && ruleRoute.Redirect == nil { - ruleRoute.DirectResponse = &ir.CustomResponse{ - StatusCode: ptr.To(uint32(500)), - } - } - ruleRoute.IsHTTP2 = false + errs.Add(status.NewRouteStatusError( + fmt.Errorf( + "failed to process route rule %d: mixed endpointslice address type between backendRefs is not supported", + ruleIdx), + status.RouteReasonInvalidBackendRef, + )) } // TODO handle: // - sum of weights for valid backend refs is 0 // - etc. - routeRoutes = append(routeRoutes, ruleRoutes...) + irRoutes = append(irRoutes, ruleRoutes...) } - - return routeRoutes, nil + if errs.Empty() { + return irRoutes, nil + } + return irRoutes, errs } func processRouteTrafficFeatures(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) { @@ -339,7 +361,12 @@ func processRouteRetry(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) { irRoute.Retry = res } -func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx int, httpFiltersContext *HTTPFiltersContext, rule gwapiv1.HTTPRouteRule) ([]*ir.HTTPRoute, error) { +func (t *Translator) processHTTPRouteRule( + httpRoute *HTTPRouteContext, + ruleIdx int, + httpFiltersContext *HTTPFiltersContext, + rule gwapiv1.HTTPRouteRule, +) ([]*ir.HTTPRoute, status.Error) { var ruleRoutes []*ir.HTTPRoute // If no matches are specified, the implementation MUST match every HTTP request. @@ -356,7 +383,10 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i var sessionPersistence *ir.SessionPersistence if rule.SessionPersistence != nil { if rule.SessionPersistence.IdleTimeout != nil { - return nil, fmt.Errorf("idle timeout is not supported in envoy gateway") + return nil, status.NewRouteStatusError( + fmt.Errorf("idle timeout is not supported in envoy gateway"), + status.RouteReasonUnsupportedSetting, + ) } var sessionName string @@ -384,7 +414,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i *rule.SessionPersistence.CookieConfig.LifetimeType == gwapiv1.PermanentCookieLifetimeType { ttl, err := time.ParseDuration(string(*rule.SessionPersistence.AbsoluteTimeout)) if err != nil { - return nil, err + return nil, status.NewRouteStatusError(err, gwapiv1.RouteReasonUnsupportedValue) } sessionPersistence.Cookie.TTL = &metav1.Duration{Duration: ttl} } @@ -396,7 +426,10 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i } default: // Unknown session persistence type is specified. - return nil, fmt.Errorf("unknown session persistence type %s", *rule.SessionPersistence.Type) + return nil, status.NewRouteStatusError( + fmt.Errorf("unknown session persistence type %s", *rule.SessionPersistence.Type), + gwapiv1.RouteReasonUnsupportedValue, + ) } } @@ -423,7 +456,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i } case gwapiv1.PathMatchRegularExpression: if err := regex.Validate(*match.Path.Value); err != nil { - return nil, err + return nil, status.NewRouteStatusError(err, gwapiv1.RouteReasonUnsupportedValue) } irRoute.PathMatch = &ir.StringMatch{ SafeRegex: match.Path.Value, @@ -439,7 +472,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i }) case gwapiv1.HeaderMatchRegularExpression: if err := regex.Validate(headerMatch.Value); err != nil { - return nil, err + return nil, status.NewRouteStatusError(err, gwapiv1.RouteReasonUnsupportedValue) } irRoute.HeaderMatches = append(irRoute.HeaderMatches, &ir.StringMatch{ Name: string(headerMatch.Name), @@ -456,7 +489,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i }) case gwapiv1.QueryParamMatchRegularExpression: if err := regex.Validate(queryParamMatch.Value); err != nil { - return nil, err + return nil, status.NewRouteStatusError(err, gwapiv1.RouteReasonUnsupportedValue) } irRoute.QueryParamMatches = append(irRoute.QueryParamMatches, &ir.StringMatch{ Name: string(queryParamMatch.Name), @@ -1273,7 +1306,7 @@ func (t *Translator) processTCPRouteParentRefs(tcpRoute *TCPRouteContext, resour // This will result in a direct 500 response for HTTP-based requests. func (t *Translator) processDestination(name string, backendRefContext BackendRefContext, parentRef *RouteParentContext, route RouteContext, resources *resource.Resources, -) (ds *ir.DestinationSetting, err error) { +) (ds *ir.DestinationSetting, err status.Error) { routeType := GetRouteType(route) weight := uint32(1) backendRef := GetBackendRef(backendRefContext) @@ -1317,7 +1350,8 @@ func (t *Translator) processDestination(name string, backendRefContext BackendRe ds = t.processBackendDestinationSetting(name, backendRef.BackendObjectReference, backendNamespace, protocol, resources) } - ds.TLS, err = t.applyBackendTLSSetting( + var tlsErr error + ds.TLS, tlsErr = t.applyBackendTLSSetting( backendRef.BackendObjectReference, backendNamespace, gwapiv1a2.ParentReference{ @@ -1331,13 +1365,14 @@ func (t *Translator) processDestination(name string, backendRefContext BackendRe resources, envoyProxy, ) - if err != nil { - return nil, err + if tlsErr != nil { + return nil, status.NewRouteStatusError(tlsErr, status.RouteReasonInvalidBackendTLS) } - ds.Filters, err = t.processDestinationFilters(routeType, backendRefContext, parentRef, route, resources) - if err != nil { - return nil, err + var filtersErr error + ds.Filters, filtersErr = t.processDestinationFilters(routeType, backendRefContext, parentRef, route, resources) + if filtersErr != nil { + return nil, status.NewRouteStatusError(filtersErr, status.RouteReasonInvalidBackendFilters) } if err := validateDestinationSettings(ds, t.IsEnvoyServiceRouting(envoyProxy), backendRef.Kind); err != nil { @@ -1356,16 +1391,20 @@ func (t *Translator) processDestination(name string, backendRefContext BackendRe return ds, nil } -func validateDestinationSettings(destinationSettings *ir.DestinationSetting, endpointRoutingDisabled bool, kind *gwapiv1.Kind) error { +func validateDestinationSettings(destinationSettings *ir.DestinationSetting, endpointRoutingDisabled bool, kind *gwapiv1.Kind) status.Error { // TODO: support mixed endpointslice address type for the same backendRef switch KindDerefOr(kind, resource.KindService) { case egv1a1.KindBackend: if destinationSettings.AddressType != nil && *destinationSettings.AddressType == ir.MIXED { - return fmt.Errorf("mixed FQDN and IP or Unix address type for the same backendRef is not supported") + return status.NewRouteStatusError( + fmt.Errorf("mixed FQDN and IP or Unix address type for the same backendRef is not supported"), + status.RouteReasonUnsupportedAddressType) } case resource.KindService, resource.KindServiceImport: if !endpointRoutingDisabled && destinationSettings.AddressType != nil && *destinationSettings.AddressType == ir.MIXED { - return fmt.Errorf("mixed endpointslice address type for the same backendRef is not supported") + return status.NewRouteStatusError( + fmt.Errorf("mixed endpointslice address type for the same backendRef is not supported"), + status.RouteReasonUnsupportedAddressType) } } @@ -1767,7 +1806,13 @@ func getTargetBackendReference(backendRef gwapiv1a2.BackendObjectReference, back return ref } -func (t *Translator) processBackendDestinationSetting(name string, backendRef gwapiv1.BackendObjectReference, backendNamespace string, protocol ir.AppProtocol, resources *resource.Resources) *ir.DestinationSetting { +func (t *Translator) processBackendDestinationSetting( + name string, + backendRef gwapiv1.BackendObjectReference, + backendNamespace string, + protocol ir.AppProtocol, + resources *resource.Resources, +) *ir.DestinationSetting { var ( dstEndpoints []*ir.DestinationEndpoint dstAddrType *ir.DestinationAddressType @@ -1776,6 +1821,8 @@ func (t *Translator) processBackendDestinationSetting(name string, backendRef gw addrTypeMap := make(map[ir.DestinationAddressType]int) backend := resources.GetBackend(backendNamespace, string(backendRef.Name)) + ds := &ir.DestinationSetting{Name: name} + for _, bep := range backend.Spec.Endpoints { var irde *ir.DestinationEndpoint switch { @@ -1818,13 +1865,9 @@ func (t *Translator) processBackendDestinationSetting(name string, backendRef gw for _, ap := range backend.Spec.AppProtocols { protocol = backendAppProtocolToIRAppProtocol(ap, protocol) } - - ds := &ir.DestinationSetting{ - Name: name, - Protocol: protocol, - Endpoints: dstEndpoints, - AddressType: dstAddrType, - } + ds.Endpoints = dstEndpoints + ds.AddressType = dstAddrType + ds.Protocol = protocol if backend.Spec.Fallback != nil { // set only the secondary priority, the backend defaults to a primary priority if unset. diff --git a/internal/gatewayapi/status/error.go b/internal/gatewayapi/status/error.go new file mode 100644 index 0000000000..bcad0e7510 --- /dev/null +++ b/internal/gatewayapi/status/error.go @@ -0,0 +1,190 @@ +// Copyright Envoy Gateway Authors +// SPDX-License-Identifier: Apache-2.0 +// The full text of the Apache license is available in the LICENSE file at +// the root of the repo. + +package status + +import ( + "sort" + "strings" + + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +// Route condition reasons for various error scenarios +const ( + // Route configuration related reasons + RouteReasonUnsupportedSetting gwapiv1.RouteConditionReason = "UnsupportedValue" + RouteReasonUnsupportedRefValue gwapiv1.RouteConditionReason = "UnsupportedRefValue" + + // Backend reference related reasons + RouteReasonInvalidBackendRef gwapiv1.RouteConditionReason = "InvalidBackendRef" + RouteReasonInvalidBackendTLS gwapiv1.RouteConditionReason = "InvalidBackendTLS" + RouteReasonInvalidBackendFilters gwapiv1.RouteConditionReason = "InvalidBackendFilters" + + // Network configuration related reasons + RouteReasonPortNotFound gwapiv1.RouteConditionReason = "PortNotFound" + RouteReasonPortNotSpecified gwapiv1.RouteConditionReason = "PortNotSpecified" + RouteReasonUnsupportedAddressType gwapiv1.RouteConditionReason = "UnsupportedAddressType" + RouteReasonInvalidAddress gwapiv1.RouteConditionReason = "InvalidAddress" +) + +// Error is an error interface that represents errors that need to be reflected +// in the status of a Kubernetes resource. It extends the standard error interface +// with a Reason method that returns the specific condition reason. +type Error interface { + error + Reason() gwapiv1.RouteConditionReason + Type() gwapiv1.RouteConditionType +} + +// RouteStatusError represents an error that needs to be reflected in the status of an xRoute. +// It wraps an underlying error and provides a specific route condition reason. +type RouteStatusError struct { + Wrapped error + RouteConditionReason gwapiv1.RouteConditionReason + RouteConditionType gwapiv1.RouteConditionType +} + +// NewRouteStatusError creates a new RouteStatusError with the given wrapped error and route condition reason. +func NewRouteStatusError(wrapped error, reason gwapiv1.RouteConditionReason) *RouteStatusError { + return &RouteStatusError{ + Wrapped: wrapped, + RouteConditionReason: reason, + } +} + +func (s *RouteStatusError) WithType(t gwapiv1.RouteConditionType) *RouteStatusError { + s.RouteConditionType = t + return s +} + +// Error returns the string representation of the error. +// If Wrapped is nil, it returns the string representation of the RouteConditionReason. +func (s *RouteStatusError) Error() string { + if s == nil { + return "" + } + if s.Wrapped != nil { + return s.Wrapped.Error() + } + return string(s.RouteConditionReason) +} + +// Reason returns the route condition reason associated with this error. +func (s *RouteStatusError) Reason() gwapiv1.RouteConditionReason { + if s == nil { + return "" + } + return s.RouteConditionReason +} + +// Type returns the route condition type associated with this error. +func (s *RouteStatusError) Type() gwapiv1.RouteConditionType { + // Default to ResolvedRefs because it's the most common type. + if s == nil { + return gwapiv1.RouteConditionResolvedRefs + } + return s.RouteConditionType +} + +// MultiStatusError represents a collection of status errors that occurred during processing. +// It implements the StatusError interface and provides methods to manage multiple errors. +type MultiStatusError struct { + errs []Error +} + +// Empty returns true if there are no errors in the collection. +func (m *MultiStatusError) Empty() bool { + return m == nil || len(m.errs) == 0 +} + +// Add appends a new status error to the collection. +// If the error is nil, it is ignored. +func (m *MultiStatusError) Add(err Error) { + if err == nil { + return + } + if m == nil { + m = &MultiStatusError{} + } + m.errs = append(m.errs, err) +} + +// Error returns a string representation of all the wrapped errors. +// If there are no errors, it returns an empty string. +func (m *MultiStatusError) Error() string { + if m == nil || len(m.errs) == 0 { + return "" + } + if len(m.errs) == 1 { + return m.errs[0].Error() + } + + var b strings.Builder + b.WriteString(Error2ConditionMsg(m.errs[0])) + for _, err := range m.errs[1:] { + b.WriteByte('\n') + b.WriteString(Error2ConditionMsg(err)) + } + return b.String() +} + +// Reason returns a string representation of all unique reasons from the wrapped errors. +// If there are no errors or no reasons, it returns an empty string. +func (m *MultiStatusError) Reason() gwapiv1.RouteConditionReason { + if m == nil || len(m.errs) == 0 { + return "" + } + + reasons := make(map[string]struct{}) + for _, err := range m.errs { + if reason := err.Reason(); reason != "" { + reasons[string(reason)] = struct{}{} + } + } + + if len(reasons) == 0 { + return "" + } + + reasonList := make([]string, 0, len(reasons)) + for reason := range reasons { + reasonList = append(reasonList, reason) + } + sort.Strings(reasonList) + return gwapiv1.RouteConditionReason(strings.Join(reasonList, ", ")) +} + +func (m *MultiStatusError) Type() gwapiv1.RouteConditionType { + if m == nil || len(m.errs) == 0 { + return gwapiv1.RouteConditionResolvedRefs + } + for _, err := range m.errs { + if err.Type() == gwapiv1.RouteConditionAccepted { + return gwapiv1.RouteConditionAccepted + } + } + return gwapiv1.RouteConditionResolvedRefs +} + +func isAcceptedReason(reason gwapiv1.RouteConditionReason) bool { + return reason == gwapiv1.RouteReasonNotAllowedByListeners || + reason == gwapiv1.RouteReasonNoMatchingListenerHostname || + reason == gwapiv1.RouteReasonNoMatchingParent || + reason == gwapiv1.RouteReasonUnsupportedValue +} + +// ConvertToAcceptedReason converts ResolvedRefs reasons to Accepted condition reasons +// This is used to make the reasons compatible with the Gateway API spec. +// For example, the BackendRefs validation may return a InvalidBackendRef reason for a Mirror filter validation, +// but this error should be reflected in the Accepted condition as UnsupportedValue. +func ConvertToAcceptedReason(reason gwapiv1.RouteConditionReason) gwapiv1.RouteConditionReason { + if isAcceptedReason(reason) { + return reason + } + // Return UnsupportedValue as the default reason for ResolvedRefs reasons, which is kind of vague and can be used for + // any other reasons. + return gwapiv1.RouteReasonUnsupportedValue +} diff --git a/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml b/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml index 6a82f655a8..c18041a2e7 100644 --- a/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml +++ b/internal/gatewayapi/testdata/backend-invalid-feature-disabled.out.yaml @@ -121,7 +121,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Backend is disabled in Envoy Gateway configuration + message: 'Failed to process route rule 0 backendRef 0: Backend is disabled + in Envoy Gateway configuration.' reason: UnsupportedValue status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/backendtlspolicy-invalid-ca.out.yaml b/internal/gatewayapi/testdata/backendtlspolicy-invalid-ca.out.yaml index 50ae45b793..8584f51b3b 100644 --- a/internal/gatewayapi/testdata/backendtlspolicy-invalid-ca.out.yaml +++ b/internal/gatewayapi/testdata/backendtlspolicy-invalid-ca.out.yaml @@ -101,9 +101,10 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" + message: 'Failed to process route rule 0 backendRef 0: no ca found in configmap + no-ca-cmap.' + reason: InvalidBackendTLS + status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: diff --git a/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.in.yaml b/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.in.yaml index 96a97fcb0c..ac044ec42c 100644 --- a/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.in.yaml +++ b/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.in.yaml @@ -72,6 +72,28 @@ services: protocol: TCP targetPort: 8081 +endpointSlices: + - apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + name: endpointslice-http-backend + namespace: envoy-gateway + labels: + kubernetes.io/service-name: http-backend + addressType: IPv4 + ports: + - name: http1 + protocol: TCP + port: 8080 + - name: http2 + protocol: TCP + port: 8081 + endpoints: + - addresses: + - "10.244.0.11" + conditions: + ready: true + configMaps: - apiVersion: v1 kind: ConfigMap diff --git a/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.out.yaml b/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.out.yaml index 268c7f71bf..b993b50455 100644 --- a/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.out.yaml +++ b/internal/gatewayapi/testdata/backendtlspolicy-multiple-targets.out.yaml @@ -192,7 +192,11 @@ xdsIR: - destination: name: httproute/envoy-gateway/httproute-btls-1/rule/0 settings: - - name: httproute/envoy-gateway/httproute-btls-1/rule/0/backend/0 + - addressType: IP + endpoints: + - host: 10.244.0.11 + port: 8080 + name: httproute/envoy-gateway/httproute-btls-1/rule/0/backend/0 protocol: HTTP tls: alpnProtocols: null @@ -201,8 +205,6 @@ xdsIR: name: policy-btls/envoy-gateway-ca sni: example.com weight: 1 - directResponse: - statusCode: 500 hostname: '*' isHTTP2: false metadata: @@ -217,7 +219,11 @@ xdsIR: - destination: name: httproute/envoy-gateway/httproute-btls-2/rule/0 settings: - - name: httproute/envoy-gateway/httproute-btls-2/rule/0/backend/0 + - addressType: IP + endpoints: + - host: 10.244.0.11 + port: 8081 + name: httproute/envoy-gateway/httproute-btls-2/rule/0/backend/0 protocol: HTTP tls: alpnProtocols: null @@ -226,8 +232,6 @@ xdsIR: name: policy-btls/envoy-gateway-ca sni: example.com weight: 1 - directResponse: - statusCode: 500 hostname: '*' isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.in.yaml b/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.in.yaml index 2db186d267..7ecbdb09f7 100644 --- a/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.in.yaml +++ b/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.in.yaml @@ -82,7 +82,7 @@ endpointSlices: name: service-import-1 namespace: default labels: - kubernetes.io/service-name: service-import-1 + multicluster.kubernetes.io/service-name: service-import-1 addressType: IPv4 ports: - name: http diff --git a/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.out.yaml b/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.out.yaml index a3dfb20385..4659557c9f 100644 --- a/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.out.yaml +++ b/internal/gatewayapi/testdata/backendtlspolicy-serviceimport-target.out.yaml @@ -158,7 +158,11 @@ xdsIR: - destination: name: httproute/envoy-gateway/httproute-btls/rule/0 settings: - - name: httproute/envoy-gateway/httproute-btls/rule/0/backend/0 + - addressType: IP + endpoints: + - host: 10.244.0.11 + port: 8080 + name: httproute/envoy-gateway/httproute-btls/rule/0/backend/0 protocol: HTTP2 tls: alpnProtocols: null @@ -167,7 +171,11 @@ xdsIR: sni: example.com useSystemTrustStore: true weight: 1 - - name: httproute/envoy-gateway/httproute-btls/rule/0/backend/1 + - addressType: IP + endpoints: + - host: 10.244.0.11 + port: 9000 + name: httproute/envoy-gateway/httproute-btls/rule/0/backend/1 protocol: HTTP tls: alpnProtocols: null @@ -176,8 +184,6 @@ xdsIR: sni: example.com useSystemTrustStore: true weight: 1 - directResponse: - statusCode: 500 hostname: '*' isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml index a189199c52..863fde4c1d 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.in.yaml @@ -196,3 +196,65 @@ gateways: allowedRoutes: namespaces: from: Same + +services: +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 +- apiVersion: v1 + kind: Service + metadata: + namespace: another-namespace + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: another-namespace + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml index 1f1259870a..db5f02fdc5 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml @@ -385,9 +385,9 @@ grpcRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -420,9 +420,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -454,9 +454,9 @@ httpRoutes: status: "False" type: Accepted - lastTransitionTime: null - message: Service another-namespace/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -560,8 +560,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 hostname: '*' isHTTP2: false metadata: @@ -600,8 +608,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: grpcroute/envoy-gateway/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: grpcroute/envoy-gateway/grpcroute-1/rule/0/backend/0 + protocol: GRPC + weight: 1 headerMatches: - distinct: false exact: foo diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.in.yaml index 4da9fbe289..413102df5b 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.in.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.in.yaml @@ -62,6 +62,39 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 +services: +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true + backendTrafficPolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: BackendTrafficPolicy @@ -82,4 +115,3 @@ backendTrafficPolicies: http: connectionIdleTimeout: 16s maxConnectionDuration: 17s - diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml index 7c0b199a46..d3986837a5 100644 --- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml +++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml @@ -152,9 +152,9 @@ grpcRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -191,9 +191,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -252,8 +252,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: grpcroute/envoy-gateway/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: grpcroute/envoy-gateway/grpcroute-1/rule/0/backend/0 + protocol: GRPC + weight: 1 hostname: '*' isHTTP2: true metadata: @@ -294,8 +302,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 hostname: gateway.envoyproxy.io isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-http10.in.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-http10.in.yaml index c4f16d4a2a..9a95f4113f 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-http10.in.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-http10.in.yaml @@ -150,3 +150,35 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 +services: +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/clienttrafficpolicy-http10.out.yaml b/internal/gatewayapi/testdata/clienttrafficpolicy-http10.out.yaml index e9a07af17f..4282fed573 100644 --- a/internal/gatewayapi/testdata/clienttrafficpolicy-http10.out.yaml +++ b/internal/gatewayapi/testdata/clienttrafficpolicy-http10.out.yaml @@ -341,9 +341,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -357,9 +357,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -395,9 +395,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -520,8 +520,16 @@ xdsIR: mergeSlashes: true port: 8082 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 hostname: route.example.com isHTTP2: false metadata: @@ -549,7 +557,17 @@ xdsIR: mergeSlashes: true port: 8083 routes: - - directResponse: + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 + directResponse: statusCode: 500 hostname: route.example.com isHTTP2: false @@ -562,7 +580,17 @@ xdsIR: distinct: false name: "" prefix: / - - directResponse: + - destination: + name: httproute/envoy-gateway/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-2/rule/0/backend/0 + protocol: HTTP + weight: 1 + directResponse: statusCode: 500 hostname: route2.example.com isHTTP2: false diff --git a/internal/gatewayapi/testdata/custom-filter-order.in.yaml b/internal/gatewayapi/testdata/custom-filter-order.in.yaml index 6f27637135..59c44d469a 100644 --- a/internal/gatewayapi/testdata/custom-filter-order.in.yaml +++ b/internal/gatewayapi/testdata/custom-filter-order.in.yaml @@ -53,6 +53,39 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 +services: + - apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: + - apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true + securityPolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: SecurityPolicy diff --git a/internal/gatewayapi/testdata/custom-filter-order.out.yaml b/internal/gatewayapi/testdata/custom-filter-order.out.yaml index 98a46d7ee0..f37742ea78 100644 --- a/internal/gatewayapi/testdata/custom-filter-order.out.yaml +++ b/internal/gatewayapi/testdata/custom-filter-order.out.yaml @@ -116,9 +116,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -240,8 +240,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 envoyExtensions: wasms: - config: diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml index e0cf2363bc..2554c33cbe 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.in.yaml @@ -196,3 +196,64 @@ gateways: allowedRoutes: namespaces: from: Same +services: +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 +- apiVersion: v1 + kind: Service + metadata: + namespace: another-namespace + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: another-namespace + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml index 5418c20e84..66f30a694c 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-status-conditions.out.yaml @@ -385,9 +385,9 @@ grpcRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -420,9 +420,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -454,9 +454,9 @@ httpRoutes: status: "False" type: Accepted - lastTransitionTime: null - message: Service another-namespace/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -560,8 +560,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 envoyExtensions: {} hostname: '*' isHTTP2: false @@ -599,8 +607,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: grpcroute/envoy-gateway/grpcroute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: grpcroute/envoy-gateway/grpcroute-1/rule/0/backend/0 + protocol: GRPC + weight: 1 envoyExtensions: {} headerMatches: - distinct: false diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.in.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.in.yaml index 17026ebbad..c93780dc74 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.in.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.in.yaml @@ -52,12 +52,45 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 +services: +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true + envoyextensionpolicies: - apiVersion: gateway.envoyproxy.io/v1alpha1 kind: EnvoyExtensionPolicy metadata: namespace: envoy-gateway - name: policy-for-gateway # This policy should attach httproute-2 + name: policy-for-gateway # This policy should attach httproute-2 spec: targetRefs: - group: gateway.networking.k8s.io diff --git a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml index 00b8255afa..0ea7be373d 100644 --- a/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml +++ b/internal/gatewayapi/testdata/envoyextensionpolicy-with-wasm-targetrefs.out.yaml @@ -138,9 +138,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -176,9 +176,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -222,8 +222,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 envoyExtensions: wasms: - config: @@ -259,8 +267,16 @@ xdsIR: distinct: false name: "" prefix: /foo - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-2/rule/0/backend/0 + protocol: HTTP + weight: 1 envoyExtensions: wasms: - config: diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml index 03977e3307..0f54a65280 100644 --- a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.in.yaml @@ -215,7 +215,37 @@ services: appProtocol: grpc protocol: TCP targetPort: 9000 -endpointSlices: +- apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: +- apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true - apiVersion: discovery.k8s.io/v1 kind: EndpointSlice metadata: diff --git a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml index ca1370e0f7..8b06e25768 100644 --- a/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-accesslog-types.out.yaml @@ -67,9 +67,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -451,8 +451,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 hostname: '*' isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid-ns.out.yaml b/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid-ns.out.yaml index c37797f368..507259c65b 100644 --- a/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid-ns.out.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid-ns.out.yaml @@ -128,9 +128,11 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" + message: 'Failed to process route rule 0 backendRef 0: ClientCertificateRef + Secret is not located in the same namespace as Envoyproxy. Secret namespace: + envoy-gateway-user-ns does not match Envoyproxy namespace: envoy-gateway-system.' + reason: InvalidBackendTLS + status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: diff --git a/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid.out.yaml b/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid.out.yaml index 207ca8895d..259fa875a4 100644 --- a/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid.out.yaml +++ b/internal/gatewayapi/testdata/envoyproxy-tls-settings-invalid.out.yaml @@ -127,9 +127,11 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Resolved all the Object references for the Route - reason: ResolvedRefs - status: "True" + message: 'Failed to process route rule 0 backendRef 0: failed to locate TLS + secret for client auth: envoy-gateway-system/client-auth-not-found specified + in EnvoyProxy envoy-gateway-system/test.' + reason: InvalidBackendTLS + status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: diff --git a/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml b/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml index 8fba772492..83d7f940ae 100644 --- a/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml +++ b/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.in.yaml @@ -63,3 +63,35 @@ httpRoutes: backendRefs: - name: service-1 port: 8080 +services: + - apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: + - apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.out.yaml b/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.out.yaml index 5ba73049e9..711c638280 100644 --- a/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.out.yaml +++ b/internal/gatewayapi/testdata/gateway-http-listener-with-hostname-intersection.out.yaml @@ -101,9 +101,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -141,9 +141,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found - reason: BackendNotFound - status: "False" + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: @@ -187,8 +187,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-1/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-1/rule/0/backend/0 + protocol: HTTP + weight: 1 hostname: bar.com isHTTP2: false metadata: @@ -215,8 +223,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/httproute-2/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/httproute-2/rule/0/backend/0 + protocol: HTTP + weight: 1 hostname: '*.example.com' isHTTP2: false metadata: diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml index fef198ced0..7977e60505 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-tcproute-with-mismatch-port-protocol.out.yaml @@ -72,8 +72,7 @@ tcpRoutes: parents: - conditions: - lastTransitionTime: null - message: 'backend Service validation failed: TCP Port 8081 not found on Service - default/service-1' + message: TCP Port 8081 not found on Service default/service-1 reason: Failed to process the settings associated with the TCP route. status: "False" type: Accepted diff --git a/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml b/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml index 2bb2d0194e..77be96536e 100644 --- a/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml +++ b/internal/gatewayapi/testdata/gateway-with-listener-with-udproute-with-mismatch-port-protocol.out.yaml @@ -72,8 +72,7 @@ udpRoutes: parents: - conditions: - lastTransitionTime: null - message: 'backend Service validation failed: UDP Port 8080 not found on Service - default/service-1' + message: UDP Port 8080 not found on Service default/service-1 reason: Failed to process the settings associated with the UDP route. status: "False" type: Accepted diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml index fb128b0413..495fe02e2e 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref-mixed-address-type.out.yaml @@ -151,8 +151,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Unix domain sockets are not supported in backend references - reason: UnsupportedRefAddressFound + message: 'Failed to process route rule 0 backendRef 0: unix domain sockets + are not supported in backend references.' + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller @@ -188,9 +189,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: mixed FQDN and IP or Unix address type for the same backendRef is - not supported - reason: ResolvedRefs + message: 'Failed to process route rule 0 backendRef 0: mixed FQDN and IP or + Unix address type for the same backendRef is not supported.' + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller @@ -226,9 +227,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: mixed FQDN and IP or Unix address type for the same backendRef is - not supported - reason: ResolvedRefs + message: 'Failed to process route rule 0 backendRef 0: mixed FQDN and IP or + Unix address type for the same backendRef is not supported.' + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml index b2e8aa5f37..a6956ae1ca 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-backend-backendref.out.yaml @@ -160,8 +160,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Unix domain sockets are not supported in backend references - reason: UnsupportedRefAddressFound + message: 'Failed to process route rule 0 backendRef 0: unix domain sockets + are not supported in backend references.' + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller @@ -271,9 +272,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: 'Invalid backend reference: IP address 127.0.0.1 in the loopback - range is not supported' - reason: UnsupportedRefAddressFound + message: 'Failed to process route rule 0 backendRef 0: IP address 127.0.0.1 + in the loopback range is not supported.' + reason: InvalidAddress status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller @@ -309,9 +310,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: 'Invalid backend reference: hostname localhost should be a domain - with at least two segments separated by dots' - reason: UnsupportedRefAddressFound + message: 'Failed to process route rule 0 backendRef 0: hostname localhost + should be a domain with at least two segments separated by dots.' + reason: InvalidAddress status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml index 6163f16ded..5921a8c47a 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-diff-address-type.out.yaml @@ -128,8 +128,10 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Mixed endpointslice address type between backendRefs is not supported - reason: ResolvedRefs + message: |- + Failed to process route rule 0 backendRef 0: unix domain sockets are not supported in backend references. + Failed to process route rule 0: mixed endpointslice address type between backendRefs is not supported. + reason: InvalidBackendRef, UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller @@ -168,8 +170,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Unix domain sockets are not supported in backend references - reason: UnsupportedRefAddressFound + message: 'Failed to process route rule 0 backendRef 0: unix domain sockets + are not supported in backend references.' + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller @@ -208,8 +211,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Mixed endpointslice address type between backendRefs is not supported - reason: ResolvedRefs + message: 'Failed to process route rule 0: mixed endpointslice address type + between backendRefs is not supported.' + reason: InvalidBackendRef status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller @@ -248,8 +252,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Unix domain sockets are not supported in backend references - reason: UnsupportedRefAddressFound + message: 'Failed to process route rule 0 backendRef 0: unix domain sockets + are not supported in backend references.' + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml index eec8cb0e00..965a2ef450 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-backend-backendrefs-same-address-type.out.yaml @@ -178,8 +178,10 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Unix domain sockets are not supported in backend references - reason: UnsupportedRefAddressFound + message: |- + Failed to process route rule 0 backendRef 0: unix domain sockets are not supported in backend references. + Failed to process route rule 0 backendRef 1: unix domain sockets are not supported in backend references. + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-serviceimport-backendrefs-diff-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-serviceimport-backendrefs-diff-address-type.out.yaml index 696dc48cb6..84f357321f 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-serviceimport-backendrefs-diff-address-type.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-multiple-serviceimport-backendrefs-diff-address-type.out.yaml @@ -73,8 +73,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Mixed endpointslice address type between backendRefs is not supported - reason: ResolvedRefs + message: 'Failed to process route rule 0: mixed endpointslice address type + between backendRefs is not supported.' + reason: InvalidBackendRef status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller diff --git a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref-mixed-address-type.out.yaml b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref-mixed-address-type.out.yaml index b379de8d18..5e1c6631e7 100644 --- a/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref-mixed-address-type.out.yaml +++ b/internal/gatewayapi/testdata/httproute-attaching-to-listener-with-serviceimport-backendref-mixed-address-type.out.yaml @@ -69,8 +69,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: mixed endpointslice address type for the same backendRef is not supported - reason: ResolvedRefs + message: 'Failed to process route rule 0 backendRef 0: mixed endpointslice + address type for the same backendRef is not supported.' + reason: UnsupportedAddressType status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml index 38843d504f..d772df320e 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-bad-port.out.yaml @@ -67,7 +67,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: TCP Port 8888 not found on Service default/service-1 + message: 'Failed to process route rule 0 backendRef 0: TCP Port 8888 not found + on Service default/service-1.' reason: PortNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-group.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-group.out.yaml index 2a4d5bd09d..cff116987f 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-group.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-group.out.yaml @@ -69,9 +69,10 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Group is invalid, only the core API group (specified by omitting - the group field or setting it to an empty string), multicluster.x-k8s.io - and gateway.envoyproxy.io are supported + message: 'Failed to process route rule 0 backendRef 0: Group is invalid, only + the core API group (specified by omitting the group field or setting it + to an empty string), multicluster.x-k8s.io and gateway.envoyproxy.io are + supported.' reason: InvalidKind status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-kind.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-kind.out.yaml index c4dc554c58..88ee413d29 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-kind.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-kind.out.yaml @@ -68,8 +68,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Kind is invalid, only Service, MCS ServiceImport and Envoy Gateway - Backend are supported + message: 'Failed to process route rule 0 backendRef 0: Kind is invalid, only + Service, MCS ServiceImport and Envoy Gateway Backend are supported.' reason: InvalidKind status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-mixed-kind.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-mixed-kind.out.yaml index aca7b9e655..7753de766b 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-mixed-kind.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-invalid-mixed-kind.out.yaml @@ -91,8 +91,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Mixed endpointslice address type between backendRefs is not supported - reason: ResolvedRefs + message: 'Failed to process route rule 0: mixed endpointslice address type + between backendRefs is not supported.' + reason: InvalidBackendRef status: "False" type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-port.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-port.out.yaml index 34500886f2..928836b561 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-port.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-port.out.yaml @@ -66,8 +66,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: A valid port number corresponding to a port on the Service must be - specified + message: 'Failed to process route rule 0 backendRef 0: A valid port number + corresponding to a port on the Service must be specified.' reason: PortNotSpecified status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml index 4eb1ff3739..419646b49b 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.import.out.yaml @@ -69,7 +69,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service import default/service-import-that-doesnt-exist not found + message: 'Failed to process route rule 0 backendRef 0: service import default/service-import-that-doesnt-exist + not found.' reason: BackendNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.out.yaml index 0cfcafe7ba..489fbd75c1 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-no-service.out.yaml @@ -67,7 +67,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service default/service-that-doesnt-exist not found + message: 'Failed to process route rule 0 backendRef 0: service default/service-that-doesnt-exist + not found.' reason: BackendNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-unsupported-filter.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-unsupported-filter.out.yaml index e7ac021f13..a688188f5b 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-unsupported-filter.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-unsupported-filter.out.yaml @@ -73,8 +73,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Specific filter is not supported within BackendRef, only RequestHeaderModifier, - ResponseHeaderModifier and gateway.envoyproxy.io/HTTPRouteFilter are supported + message: 'Failed to process route rule 0 backendRef 0: specific filter is + not supported within BackendRef, only RequestHeaderModifier and ResponseHeaderModifier + are supported.' reason: UnsupportedRefValue status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-backendref-in-other-namespace.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-backendref-in-other-namespace.out.yaml index dcc76c54f4..043109b537 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-backendref-in-other-namespace.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-backendref-in-other-namespace.out.yaml @@ -68,7 +68,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Backend ref to Service backends/service-1 not permitted by any ReferenceGrant. + message: 'Failed to process route rule 0 backendRef 0: Backend ref to Service + backends/service-1 not permitted by any ReferenceGrant.' reason: RefNotPermitted status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/httproute-with-invalid-regex.out.yaml b/internal/gatewayapi/testdata/httproute-with-invalid-regex.out.yaml index 0a4b1b8ace..08214ca3b6 100644 --- a/internal/gatewayapi/testdata/httproute-with-invalid-regex.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-invalid-regex.out.yaml @@ -102,11 +102,16 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: 'Regex "*.foo.bar.com" is invalid: error parsing regexp: missing - argument to repetition operator: `*`.' + message: 'Failed to process route rule 0: regex "*.foo.bar.com" is invalid: + error parsing regexp: missing argument to repetition operator: `*`.' reason: UnsupportedValue status: "False" type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: name: gateway-1 diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-no-port.out.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-no-port.out.yaml index 87c69760f6..d2605efc0a 100644 --- a/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-no-port.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-no-port.out.yaml @@ -71,8 +71,9 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: 'Error validating backend port: port number not specified for backend - reference.' + message: 'Failed to process route rule 0: failed to validate the RequestMirror + filter: A valid port number corresponding to a port on the Service must + be specified.' reason: UnsupportedValue status: "False" type: Accepted diff --git a/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml b/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml index d12d21a45a..664ffd08f5 100644 --- a/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-mirror-filter-service-not-found.out.yaml @@ -72,8 +72,8 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: 'Backend Service validation failed: service default/service-unknown - not found.' + message: 'Failed to process route rule 0: failed to validate the RequestMirror + filter: service default/service-unknown not found.' reason: UnsupportedValue status: "False" type: Accepted diff --git a/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.in.yaml b/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.in.yaml index 12aa992ef4..6fe5033646 100644 --- a/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.in.yaml +++ b/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.in.yaml @@ -53,3 +53,38 @@ httpRoutes: path: type: PathPrefix value: /toy + backendRefs: + - name: service-1 + port: 8080 +services: + - apiVersion: v1 + kind: Service + metadata: + namespace: envoy-gateway + name: service-1 + spec: + selector: + app: service-1 + ports: + - name: http + protocol: TCP + port: 8080 + +endpointslices: + - apiVersion: discovery.k8s.io/v1 + kind: EndpointSlice + metadata: + namespace: envoy-gateway + name: service-1 + labels: + kubernetes.io/service-name: service-1 + addressType: IPv4 + ports: + - name: http + protocol: TCP + port: 8080 + endpoints: + - addresses: + - 7.7.7.7 + conditions: + ready: true diff --git a/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.out.yaml b/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.out.yaml index 36d163dc22..5187100b7e 100644 --- a/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-multiple-gateways-from-different-ns.out.yaml @@ -101,7 +101,10 @@ httpRoutes: kind: Gateway name: gateway-b rules: - - matches: + - backendRefs: + - name: service-1 + port: 8080 + matches: - method: GET path: type: PathPrefix @@ -193,8 +196,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/targeted-route/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/targeted-route/rule/0/backend/0 + protocol: HTTP + weight: 1 headerMatches: - distinct: false exact: GET @@ -235,8 +246,16 @@ xdsIR: mergeSlashes: true port: 10080 routes: - - directResponse: - statusCode: 500 + - destination: + name: httproute/envoy-gateway/targeted-route/rule/0 + settings: + - addressType: IP + endpoints: + - host: 7.7.7.7 + port: 8080 + name: httproute/envoy-gateway/targeted-route/rule/0/backend/0 + protocol: HTTP + weight: 1 headerMatches: - distinct: false exact: GET diff --git a/internal/gatewayapi/testdata/httproute-with-multiple-invalid-rules.in.yaml b/internal/gatewayapi/testdata/httproute-with-multiple-invalid-rules.in.yaml new file mode 100644 index 0000000000..c567b0982a --- /dev/null +++ b/internal/gatewayapi/testdata/httproute-with-multiple-invalid-rules.in.yaml @@ -0,0 +1,51 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + namespace: envoy-gateway + name: gateway-1 + spec: + gatewayClassName: envoy-gateway-class + listeners: + - name: http + protocol: HTTP + port: 80 + allowedRoutes: + namespaces: + from: All +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + namespace: default + name: httproute-1 + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - namespace: envoy-gateway + name: gateway-1 + sectionName: http + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-not-found + - matches: + - path: + value: "/foo" + backendRefs: + - name: service-not-found-1 + port: 8080 + - name: service-not-found-2 + port: 8080 + - matches: + - path: + value: "/bar" + backendRefs: + - name: serviceimport-not-found-1 + kind: ServiceImport + port: 8080 + - name: serviceimport-not-found-2 + kind: ServiceImport + port: 8080 diff --git a/internal/gatewayapi/testdata/httproute-with-multiple-invalid-rules.out.yaml b/internal/gatewayapi/testdata/httproute-with-multiple-invalid-rules.out.yaml new file mode 100644 index 0000000000..f6f07b48ef --- /dev/null +++ b/internal/gatewayapi/testdata/httproute-with-multiple-invalid-rules.out.yaml @@ -0,0 +1,178 @@ +gateways: +- apiVersion: gateway.networking.k8s.io/v1 + kind: Gateway + metadata: + creationTimestamp: null + name: gateway-1 + namespace: envoy-gateway + spec: + gatewayClassName: envoy-gateway-class + listeners: + - allowedRoutes: + namespaces: + from: All + name: http + port: 80 + protocol: HTTP + status: + listeners: + - attachedRoutes: 1 + conditions: + - lastTransitionTime: null + message: Sending translated listener configuration to the data plane + reason: Programmed + status: "True" + type: Programmed + - lastTransitionTime: null + message: Listener has been successfully translated + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: Listener references have been resolved + reason: ResolvedRefs + status: "True" + type: ResolvedRefs + name: http + supportedKinds: + - group: gateway.networking.k8s.io + kind: HTTPRoute + - group: gateway.networking.k8s.io + kind: GRPCRoute +httpRoutes: +- apiVersion: gateway.networking.k8s.io/v1 + kind: HTTPRoute + metadata: + creationTimestamp: null + name: httproute-1 + namespace: default + spec: + hostnames: + - gateway.envoyproxy.io + parentRefs: + - name: gateway-1 + namespace: envoy-gateway + sectionName: http + rules: + - backendRefs: + - group: gateway.envoyproxy.io + kind: Backend + name: backend-not-found + - backendRefs: + - name: service-not-found-1 + port: 8080 + - name: service-not-found-2 + port: 8080 + matches: + - path: + value: /foo + - backendRefs: + - kind: ServiceImport + name: serviceimport-not-found-1 + port: 8080 + - kind: ServiceImport + name: serviceimport-not-found-2 + port: 8080 + matches: + - path: + value: /bar + status: + parents: + - conditions: + - lastTransitionTime: null + message: Route is accepted + reason: Accepted + status: "True" + type: Accepted + - lastTransitionTime: null + message: |- + Failed to process route rule 0 backendRef 0: Backend default/backend-not-found not found. + Failed to process route rule 1 backendRef 0: service default/service-not-found-1 not found. + Failed to process route rule 1 backendRef 1: service default/service-not-found-2 not found. + Failed to process route rule 2 backendRef 0: service import default/serviceimport-not-found-1 not found. + Failed to process route rule 2 backendRef 1: service import default/serviceimport-not-found-2 not found. + reason: BackendNotFound + status: "False" + type: ResolvedRefs + controllerName: gateway.envoyproxy.io/gatewayclass-controller + parentRef: + name: gateway-1 + namespace: envoy-gateway + sectionName: http +infraIR: + envoy-gateway/gateway-1: + proxy: + listeners: + - address: null + name: envoy-gateway/gateway-1/http + ports: + - containerPort: 10080 + name: http-80 + protocol: HTTP + servicePort: 80 + metadata: + labels: + gateway.envoyproxy.io/owning-gateway-name: gateway-1 + gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway + name: envoy-gateway/gateway-1 +xdsIR: + envoy-gateway/gateway-1: + accessLog: + json: + - path: /dev/stdout + http: + - address: 0.0.0.0 + hostnames: + - '*' + isHTTP2: false + metadata: + kind: Gateway + name: gateway-1 + namespace: envoy-gateway + sectionName: http + name: envoy-gateway/gateway-1/http + path: + escapedSlashesAction: UnescapeAndRedirect + mergeSlashes: true + port: 10080 + routes: + - directResponse: + statusCode: 500 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/1/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /foo + - directResponse: + statusCode: 500 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/2/match/0/gateway_envoyproxy_io + pathMatch: + distinct: false + name: "" + prefix: /bar + - directResponse: + statusCode: 500 + hostname: gateway.envoyproxy.io + isHTTP2: false + metadata: + kind: HTTPRoute + name: httproute-1 + namespace: default + name: httproute/default/httproute-1/rule/0/match/-1/gateway_envoyproxy_io + readyListener: + address: 0.0.0.0 + ipFamily: IPv4 + path: /ready + port: 19003 diff --git a/internal/gatewayapi/testdata/httproute-with-single-rule-with-multiple-rules.out.yaml b/internal/gatewayapi/testdata/httproute-with-single-rule-with-multiple-rules.out.yaml index f2fa88e8ab..f766dc1a30 100644 --- a/internal/gatewayapi/testdata/httproute-with-single-rule-with-multiple-rules.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-single-rule-with-multiple-rules.out.yaml @@ -92,11 +92,16 @@ httpRoutes: parents: - conditions: - lastTransitionTime: null - message: 'Regex "*regex*" is invalid: error parsing regexp: missing argument - to repetition operator: `*`.' + message: 'Failed to process route rule 2: regex "*regex*" is invalid: error + parsing regexp: missing argument to repetition operator: `*`.' reason: UnsupportedValue status: "False" type: Accepted + - lastTransitionTime: null + message: Resolved all the Object references for the Route + reason: ResolvedRefs + status: "True" + type: ResolvedRefs controllerName: gateway.envoyproxy.io/gatewayclass-controller parentRef: name: gateway-1 diff --git a/internal/gatewayapi/testdata/httproute-with-some-invalid-backend-refs-no-service.out.yaml b/internal/gatewayapi/testdata/httproute-with-some-invalid-backend-refs-no-service.out.yaml index 5f5eb68a53..bde42466fb 100644 --- a/internal/gatewayapi/testdata/httproute-with-some-invalid-backend-refs-no-service.out.yaml +++ b/internal/gatewayapi/testdata/httproute-with-some-invalid-backend-refs-no-service.out.yaml @@ -71,7 +71,9 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service default/service-that-doesnt-exist-2 not found + message: |- + Failed to process route rule 0 backendRef 0: service default/service-that-doesnt-exist not found. + Failed to process route rule 0 backendRef 1: service default/service-that-doesnt-exist-2 not found. reason: BackendNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml index e72799b669..2380d0ae7f 100644 --- a/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-status-conditions.out.yaml @@ -194,7 +194,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found + message: 'Failed to process route rule 0 backendRef 0: service envoy-gateway/service-1 + not found.' reason: BackendNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/securitypolicy-with-cors-targetrefs.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-cors-targetrefs.out.yaml index 79efe45f4a..708a622f92 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-cors-targetrefs.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-cors-targetrefs.out.yaml @@ -183,7 +183,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-1 not found + message: 'Failed to process route rule 0 backendRef 0: service envoy-gateway/service-1 + not found.' reason: BackendNotFound status: "False" type: ResolvedRefs @@ -221,7 +222,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service envoy-gateway/service-2 not found + message: 'Failed to process route rule 0 backendRef 0: service envoy-gateway/service-2 + not found.' reason: BackendNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/testdata/securitypolicy-with-extauth-backend.out.yaml b/internal/gatewayapi/testdata/securitypolicy-with-extauth-backend.out.yaml index 3e48e76f89..947457d934 100644 --- a/internal/gatewayapi/testdata/securitypolicy-with-extauth-backend.out.yaml +++ b/internal/gatewayapi/testdata/securitypolicy-with-extauth-backend.out.yaml @@ -225,7 +225,8 @@ httpRoutes: status: "True" type: Accepted - lastTransitionTime: null - message: Service default/service-5 not found + message: 'Failed to process route rule 0 backendRef 0: service default/service-5 + not found.' reason: BackendNotFound status: "False" type: ResolvedRefs diff --git a/internal/gatewayapi/validate.go b/internal/gatewayapi/validate.go index a6b84aef0c..fc8b34aa2b 100644 --- a/internal/gatewayapi/validate.go +++ b/internal/gatewayapi/validate.go @@ -26,23 +26,23 @@ import ( func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, parentRef *RouteParentContext, route RouteContext, resources *resource.Resources, backendNamespace string, routeKind gwapiv1.Kind, -) error { +) status.Error { backendRef := GetBackendRef(backendRefContext) if err := t.validateBackendRefFilters(backendRefContext, parentRef, route, routeKind); err != nil { - return fmt.Errorf("error validating backend filters: %w", err) + return err } if err := t.validateBackendRefGroup(backendRef, parentRef, route); err != nil { - return fmt.Errorf("error validating backend group: %w", err) + return err } if err := t.validateBackendRefKind(backendRef, parentRef, route); err != nil { - return fmt.Errorf("error validating backend kind: %w", err) + return err } if err := t.validateBackendNamespace(backendRef, parentRef, route, resources, routeKind); err != nil { - return fmt.Errorf("error validating backend namespace: %w", err) + return err } if err := t.validateBackendPort(backendRef, parentRef, route); err != nil { - return fmt.Errorf("error validating backend port: %w", err) + return err } protocol := corev1.ProtocolTCP @@ -50,46 +50,47 @@ func (t *Translator) validateBackendRef(backendRefContext BackendRefContext, par protocol = corev1.ProtocolUDP } + // TODO: zhaohuabing remove this and handle status in the out layer backendRefKind := KindDerefOr(backendRef.Kind, resource.KindService) switch backendRefKind { case resource.KindService: - if reason, err := validateBackendRefService(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil { + if err := validateBackendRefService(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil { routeStatus := GetRouteStatus(route) status.SetRouteStatusCondition(routeStatus, parentRef.routeParentStatusIdx, route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, metav1.ConditionFalse, - reason, + err.Reason(), errorToMessage(err), ) - return fmt.Errorf("backend Service validation failed: %w", err) + return err } case resource.KindServiceImport: - if reason, err := t.validateBackendServiceImport(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil { + if err := t.validateBackendServiceImport(backendRef.BackendObjectReference, resources, backendNamespace, protocol); err != nil { routeStatus := GetRouteStatus(route) status.SetRouteStatusCondition(routeStatus, parentRef.routeParentStatusIdx, route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, metav1.ConditionFalse, - reason, + err.Reason(), errorToMessage(err), ) - return fmt.Errorf("backend ServiceImport validation failed: %w", err) + return err } case egv1a1.KindBackend: - if reason, err := t.validateBackendRefBackend(backendRef.BackendObjectReference, resources, backendNamespace, false); err != nil { + if err := t.validateBackendRefBackend(backendRef.BackendObjectReference, resources, backendNamespace, false); err != nil { routeStatus := GetRouteStatus(route) status.SetRouteStatusCondition(routeStatus, parentRef.routeParentStatusIdx, route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, metav1.ConditionFalse, - reason, + err.Reason(), errorToMessage(err), ) - return fmt.Errorf("backend reference validation failed: %w", err) + return err } } return nil @@ -105,10 +106,10 @@ func errorToMessage(err error) string { return strings.ToUpper(msg[0:1]) + msg[1:] } -func (t *Translator) validateBackendRefGroup(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) error { +func (t *Translator) validateBackendRefGroup(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) status.Error { if backendRef.Group != nil && *backendRef.Group != "" && *backendRef.Group != GroupMultiClusterService && *backendRef.Group != egv1a1.GroupName { routeStatus := GetRouteStatus(route) - status.SetRouteStatusCondition(routeStatus, + status.SetRouteStatusCondition(routeStatus, // TODO: zhaohuabing remove this and handle status in the out layer parentRef.routeParentStatusIdx, route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, @@ -116,15 +117,19 @@ func (t *Translator) validateBackendRefGroup(backendRef *gwapiv1a2.BackendRef, p gwapiv1.RouteReasonInvalidKind, fmt.Sprintf("Group is invalid, only the core API group (specified by omitting the group field or setting it to an empty string), %s and %s are supported", GroupMultiClusterService, egv1a1.GroupName), ) - return fmt.Errorf("unsupported backend reference group: %s", *backendRef.Group) + return status.NewRouteStatusError( + fmt.Errorf("Group is invalid, only the core API group (specified by omitting the group field or setting it to an empty string), %s and %s are supported", + GroupMultiClusterService, + egv1a1.GroupName), + gwapiv1.RouteReasonInvalidKind) } return nil } -func (t *Translator) validateBackendRefKind(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) error { +func (t *Translator) validateBackendRefKind(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) status.Error { if backendRef.Kind != nil && *backendRef.Kind != resource.KindService && *backendRef.Kind != resource.KindServiceImport && *backendRef.Kind != egv1a1.KindBackend { routeStatus := GetRouteStatus(route) - status.SetRouteStatusCondition(routeStatus, + status.SetRouteStatusCondition(routeStatus, // TODO: zhaohuabing remove this and handle status in the out layer parentRef.routeParentStatusIdx, route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, @@ -132,12 +137,14 @@ func (t *Translator) validateBackendRefKind(backendRef *gwapiv1a2.BackendRef, pa gwapiv1.RouteReasonInvalidKind, "Kind is invalid, only Service, MCS ServiceImport and Envoy Gateway Backend are supported", ) - return fmt.Errorf("unsupported backend reference kind: %s", *backendRef.Kind) + return status.NewRouteStatusError( + fmt.Errorf("Kind is invalid, only Service, MCS ServiceImport and Envoy Gateway Backend are supported"), + gwapiv1.RouteReasonInvalidKind) } return nil } -func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, parentRef *RouteParentContext, route RouteContext, routeKind gwapiv1.Kind) error { +func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, parentRef *RouteParentContext, route RouteContext, routeKind gwapiv1.Kind) status.Error { filters := GetFilters(backendRef) var unsupportedFilters bool @@ -166,6 +173,7 @@ func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, par return nil } + // TODO: zhaohuabing remove this and handle status in the out layer if unsupportedFilters { message := "Specific filter is not supported within BackendRef, only RequestHeaderModifier, ResponseHeaderModifier and gateway.envoyproxy.io/HTTPRouteFilter are supported" if routeKind == resource.KindGRPCRoute { @@ -177,10 +185,12 @@ func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, par route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, metav1.ConditionFalse, - "UnsupportedRefValue", + status.RouteReasonUnsupportedRefValue, message, ) - return errors.New("unsupported filter type in backend reference") + return status.NewRouteStatusError( + errors.New("specific filter is not supported within BackendRef, only RequestHeaderModifier and ResponseHeaderModifier are supported"), + status.RouteReasonUnsupportedRefValue) } return nil @@ -188,7 +198,7 @@ func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, par func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext, resources *resource.Resources, routeKind gwapiv1.Kind, -) error { +) status.Error { if backendRef.Namespace != nil && string(*backendRef.Namespace) != "" && string(*backendRef.Namespace) != route.GetNamespace() { if !t.validateCrossNamespaceRef( crossNamespaceFrom{ @@ -205,7 +215,7 @@ func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef, resources.ReferenceGrants, ) { routeStatus := GetRouteStatus(route) - status.SetRouteStatusCondition(routeStatus, + status.SetRouteStatusCondition(routeStatus, // TODO: zhaohuabing remove this and handle status in the out layer parentRef.routeParentStatusIdx, route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, @@ -213,13 +223,18 @@ func (t *Translator) validateBackendNamespace(backendRef *gwapiv1a2.BackendRef, gwapiv1.RouteReasonRefNotPermitted, fmt.Sprintf("Backend ref to %s %s/%s not permitted by any ReferenceGrant.", KindDerefOr(backendRef.Kind, resource.KindService), *backendRef.Namespace, backendRef.Name), ) - return fmt.Errorf("cross-namespace reference not permitted for backend: %s", backendRef.Name) + return status.NewRouteStatusError( + fmt.Errorf("Backend ref to %s %s/%s not permitted by any ReferenceGrant.", + KindDerefOr(backendRef.Kind, resource.KindService), + *backendRef.Namespace, + backendRef.Name), + gwapiv1.RouteReasonRefNotPermitted) } } return nil } -func (t *Translator) validateBackendPort(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) error { +func (t *Translator) validateBackendPort(backendRef *gwapiv1a2.BackendRef, parentRef *RouteParentContext, route RouteContext) status.Error { if backendRef == nil { return nil } @@ -229,26 +244,31 @@ func (t *Translator) validateBackendPort(backendRef *gwapiv1a2.BackendRef, paren } if backendRef.Port == nil { + // TODO: zhaohuabing remove this and handle status in the out layer routeStatus := GetRouteStatus(route) status.SetRouteStatusCondition(routeStatus, parentRef.routeParentStatusIdx, route.GetGeneration(), gwapiv1.RouteConditionResolvedRefs, metav1.ConditionFalse, - "PortNotSpecified", + status.RouteReasonPortNotSpecified, "A valid port number corresponding to a port on the Service must be specified", ) - return errors.New("port number not specified for backend reference") + return status.NewRouteStatusError( + errors.New("A valid port number corresponding to a port on the Service must be specified"), + status.RouteReasonPortNotSpecified) } return nil } func validateBackendRefService(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources, serviceNamespace string, protocol corev1.Protocol, -) (gwapiv1.RouteConditionReason, error) { +) status.Error { service := resources.GetService(serviceNamespace, string(backendRef.Name)) if service == nil { - return gwapiv1.RouteReasonBackendNotFound, fmt.Errorf("service %s/%s not found", serviceNamespace, string(backendRef.Name)) + return status.NewRouteStatusError( + fmt.Errorf("service %s/%s not found", serviceNamespace, string(backendRef.Name)), + gwapiv1.RouteReasonBackendNotFound) } var portFound bool for _, port := range service.Spec.Ports { @@ -263,17 +283,21 @@ func validateBackendRefService(backendRef gwapiv1a2.BackendObjectReference, reso } if !portFound { - return "PortNotFound", fmt.Errorf("%s Port %d not found on Service %s/%s", string(protocol), *backendRef.Port, serviceNamespace, string(backendRef.Name)) + return status.NewRouteStatusError( + fmt.Errorf("%s Port %d not found on Service %s/%s", string(protocol), *backendRef.Port, serviceNamespace, string(backendRef.Name)), + status.RouteReasonPortNotFound) } - return "", nil + return nil } func (t *Translator) validateBackendServiceImport(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources, serviceImportNamespace string, protocol corev1.Protocol, -) (gwapiv1.RouteConditionReason, error) { +) status.Error { serviceImport := resources.GetServiceImport(serviceImportNamespace, string(backendRef.Name)) if serviceImport == nil { - return gwapiv1.RouteReasonBackendNotFound, fmt.Errorf("service import %s/%s not found", serviceImportNamespace, backendRef.Name) + return status.NewRouteStatusError( + fmt.Errorf("service import %s/%s not found", serviceImportNamespace, backendRef.Name), + gwapiv1.RouteReasonBackendNotFound) } var portFound bool @@ -289,35 +313,46 @@ func (t *Translator) validateBackendServiceImport(backendRef gwapiv1a2.BackendOb } if !portFound { - return "PortNotFound", fmt.Errorf("%s port %d not found on service import %s/%s", string(protocol), *backendRef.Port, serviceImportNamespace, backendRef.Name) + return status.NewRouteStatusError( + fmt.Errorf("%s port %d not found on service import %s/%s", string(protocol), *backendRef.Port, serviceImportNamespace, backendRef.Name), + status.RouteReasonPortNotFound) } - return "", nil + return nil } func (t *Translator) validateBackendRefBackend(backendRef gwapiv1a2.BackendObjectReference, resources *resource.Resources, backendNamespace string, allowUDS bool, -) (gwapiv1.RouteConditionReason, error) { +) status.Error { if !t.BackendEnabled { - return gwapiv1.RouteReasonUnsupportedValue, errors.New("backend is disabled in Envoy Gateway configuration") + return status.NewRouteStatusError( + errors.New("Backend is disabled in Envoy Gateway configuration"), + gwapiv1.RouteReasonUnsupportedValue, + ) } backend := resources.GetBackend(backendNamespace, string(backendRef.Name)) if backend == nil { - return gwapiv1.RouteReasonBackendNotFound, fmt.Errorf("backend %s/%s not found", backendNamespace, backendRef.Name) + return status.NewRouteStatusError( + fmt.Errorf("Backend %s/%s not found", backendNamespace, backendRef.Name), + gwapiv1.RouteReasonBackendNotFound, + ) } if err := validateBackend(backend); err != nil { - return "UnsupportedRefAddressFound", fmt.Errorf("invalid backend reference: %w", err) + return err } for _, bep := range backend.Spec.Endpoints { if bep.Unix != nil && !allowUDS { - return "UnsupportedRefAddressFound", errors.New("unix domain sockets are not supported in backend references") + return status.NewRouteStatusError( + errors.New("unix domain sockets are not supported in backend references"), + status.RouteReasonUnsupportedAddressType, + ) } } - return "", nil + return nil } func (t *Translator) validateListenerConditions(listener *ListenerContext) (isReady bool) { @@ -1051,6 +1086,10 @@ func (t *Translator) validateExtServiceBackendReference( if backend == nil { return fmt.Errorf("backend %s/%s not found", backendNamespace, backendRef.Name) } + // Dynamic resolver backend is not supported for EG policies + if backend.Spec.Type != nil && *backend.Spec.Type == egv1a1.BackendTypeDynamicResolver { + return fmt.Errorf("dynamic resolver backend %s/%s is not supported", backendNamespace, backendRef.Name) + } } // check if the cross-namespace reference is permitted