Skip to content

Add support for backendref service appProtocol #3511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/controller/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ func registerControllers(
objectType: &apiv1.Service{},
name: "user-service", // unique controller names are needed and we have multiple Service ctlrs
options: []controller.Option{
controller.WithK8sPredicate(predicate.ServicePortsChangedPredicate{}),
controller.WithK8sPredicate(predicate.ServiceChangedPredicate{}),
},
},
{
Expand Down
11 changes: 11 additions & 0 deletions internal/controller/state/conditions/conditions.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,17 @@
}
}

// NewRouteBackendRefUnsupportedProtocol returns a Condition that indicates that the Route has a backendRef with
// an unsupported protocol.
func NewRouteBackendRefUnsupportedProtocol(msg string) Condition {
return Condition{
Type: string(v1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse,
Reason: string(v1.RouteReasonUnsupportedProtocol),
Message: msg,
}

Check warning on line 409 in internal/controller/state/conditions/conditions.go

View check run for this annotation

Codecov / codecov/patch

internal/controller/state/conditions/conditions.go#L403-L409

Added lines #L403 - L409 were not covered by tests
}

// NewRouteInvalidGateway returns a Condition that indicates that the Route is not Accepted because the Gateway it
// references is invalid.
func NewRouteInvalidGateway() Condition {
Expand Down
69 changes: 69 additions & 0 deletions internal/controller/state/graph/backend_refs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import (
"github.com/nginx/nginx-gateway-fabric/internal/framework/helpers"
)

const (
AppProtocolTypeH2C string = "kubernetes.io/h2c"
AppProtocolTypeWS string = "kubernetes.io/ws"
AppProtocolTypeWSS string = "kubernetes.io/wss"
)

// BackendRef is an internal representation of a backendRef in an HTTP/GRPC/TLSRoute.
type BackendRef struct {
// BackendTLSPolicy is the BackendTLSPolicy of the Service which is referenced by the backendRef.
Expand Down Expand Up @@ -200,6 +206,23 @@ func createBackendRef(
return backendRef, append(conds, conditions.NewRouteBackendRefUnsupportedValue(err.Error()))
}

if svcPort.AppProtocol != nil {
err = validateRouteBackendRefAppProtocol(route.RouteType, *svcPort.AppProtocol, backendTLSPolicy)
if err != nil {
backendRef := BackendRef{
SvcNsName: svcNsName,
BackendTLSPolicy: backendTLSPolicy,
ServicePort: svcPort,
Weight: weight,
Valid: false,
IsMirrorBackend: ref.MirrorBackendIdx != nil,
InvalidForGateways: invalidForGateways,
}

return backendRef, append(conds, conditions.NewRouteBackendRefUnsupportedProtocol(err.Error()))
}
}

backendRef := BackendRef{
SvcNsName: svcNsName,
BackendTLSPolicy: backendTLSPolicy,
Expand Down Expand Up @@ -414,6 +437,52 @@ func validateBackendRef(
return true, conditions.Condition{}
}

// validateRouteBackendRefAppProtocol checks if a given RouteType supports sending traffic to a service AppProtocol.
// Returns nil if true or AppProtocol is not a Kubernetes Standard Application Protocol.
func validateRouteBackendRefAppProtocol(
routeType RouteType,
appProtocol string,
backendTLSPolicy *BackendTLSPolicy,
) error {
err := fmt.Errorf(
"route type %s does not support service port appProtocol %s",
routeType,
appProtocol,
)

// Currently we only support recognition of the Kubernetes Standard Application Protocols defined in KEP-3726.
switch appProtocol {
case AppProtocolTypeH2C:
if routeType == RouteTypeHTTP || routeType == RouteTypeGRPC {
return nil
}

return err
case AppProtocolTypeWS:
if routeType == RouteTypeHTTP {
return nil
}

return err
case AppProtocolTypeWSS:
if routeType == RouteTypeHTTP {
if backendTLSPolicy != nil {
return nil
}

return fmt.Errorf("%w; missing corresponding BackendTLSPolicy", err)
}

if routeType == RouteTypeTLS {
return nil
}

return err
}

return nil
}

func validateWeight(weight int32) error {
const (
minWeight = 0
Expand Down
Loading
Loading