Support http and https appProtocol for Kubernetes Service

This commit is contained in:
Will Da Silva 2024-10-09 10:26:04 -04:00 committed by GitHub
parent c441d04788
commit e9d677f8cb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 47 additions and 17 deletions

View file

@ -96,6 +96,7 @@ spec:
- name: web - name: web
protocol: TCP protocol: TCP
port: 8080 port: 8080
appProtocol: http
targetPort: web targetPort: web
selector: selector:
app: containous app: containous
@ -131,6 +132,8 @@ metadata:
spec: spec:
ports: ports:
- name: websecure - name: websecure
protocol: TCP
appProtocol: https
port: 443 port: 443
targetPort: websecure targetPort: websecure
selector: selector:

View file

@ -2,6 +2,7 @@ package gateway
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
@ -337,14 +338,15 @@ func (p *Provider) loadGRPCServers(namespace string, route *gatev1.GRPCRoute, ba
} }
} }
if svcPort.AppProtocol != nil && *svcPort.AppProtocol != appProtocolH2C { protocol, err := getGRPCServiceProtocol(svcPort)
if err != nil {
return nil, &metav1.Condition{ return nil, &metav1.Condition{
Type: string(gatev1.RouteConditionResolvedRefs), Type: string(gatev1.RouteConditionResolvedRefs),
Status: metav1.ConditionFalse, Status: metav1.ConditionFalse,
ObservedGeneration: route.Generation, ObservedGeneration: route.Generation,
LastTransitionTime: metav1.Now(), LastTransitionTime: metav1.Now(),
Reason: string(gatev1.RouteReasonUnsupportedProtocol), Reason: string(gatev1.RouteReasonUnsupportedProtocol),
Message: fmt.Sprintf("Cannot load GRPCBackendRef %s/%s: only kubernetes.io/h2c appProtocol is supported", namespace, backendRef.Name), Message: fmt.Sprintf("Cannot load GRPCBackendRef %s/%s: only \"kubernetes.io/h2c\" and \"https\" appProtocol is supported", namespace, backendRef.Name),
} }
} }
@ -353,7 +355,7 @@ func (p *Provider) loadGRPCServers(namespace string, route *gatev1.GRPCRoute, ba
for _, ba := range backendAddresses { for _, ba := range backendAddresses {
lb.Servers = append(lb.Servers, dynamic.Server{ lb.Servers = append(lb.Servers, dynamic.Server{
URL: fmt.Sprintf("h2c://%s", net.JoinHostPort(ba.IP, strconv.Itoa(int(ba.Port)))), URL: fmt.Sprintf("%s://%s", protocol, net.JoinHostPort(ba.IP, strconv.Itoa(int(ba.Port)))),
}) })
} }
return lb, nil return lb, nil
@ -408,3 +410,22 @@ func buildGRPCHeaderRules(headers []gatev1.GRPCHeaderMatch) []string {
return rules return rules
} }
func getGRPCServiceProtocol(portSpec corev1.ServicePort) (string, error) {
if portSpec.Protocol != corev1.ProtocolTCP {
return "", errors.New("only TCP protocol is supported")
}
if portSpec.AppProtocol == nil {
return schemeH2C, nil
}
switch ap := *portSpec.AppProtocol; ap {
case appProtocolH2C:
return schemeH2C, nil
case appProtocolHTTPS:
return schemeHTTPS, nil
default:
return "", fmt.Errorf("unsupported application protocol %s", ap)
}
}

View file

@ -468,7 +468,7 @@ func (p *Provider) loadHTTPServers(namespace string, route *gatev1.HTTPRoute, ba
} }
} }
protocol, err := getProtocol(svcPort) protocol, err := getHTTPServiceProtocol(svcPort)
if err != nil { if err != nil {
return nil, corev1.ServicePort{}, &metav1.Condition{ return nil, corev1.ServicePort{}, &metav1.Condition{
Type: string(gatev1.RouteConditionResolvedRefs), Type: string(gatev1.RouteConditionResolvedRefs),
@ -721,7 +721,7 @@ func createRequestRedirect(filter *gatev1.HTTPRequestRedirectFilter, pathMatch g
var port *string var port *string
filterScheme := ptr.Deref(filter.Scheme, "") filterScheme := ptr.Deref(filter.Scheme, "")
if filterScheme == "http" || filterScheme == "https" { if filterScheme == schemeHTTP || filterScheme == schemeHTTPS {
port = ptr.To("") port = ptr.To("")
} }
if filter.Port != nil { if filter.Port != nil {
@ -783,26 +783,26 @@ func createURLRewrite(filter *gatev1.HTTPURLRewriteFilter, pathMatch gatev1.HTTP
}, nil }, nil
} }
func getProtocol(portSpec corev1.ServicePort) (string, error) { func getHTTPServiceProtocol(portSpec corev1.ServicePort) (string, error) {
if portSpec.Protocol != corev1.ProtocolTCP { if portSpec.Protocol != corev1.ProtocolTCP {
return "", errors.New("only TCP protocol is supported") return "", errors.New("only TCP protocol is supported")
} }
if portSpec.AppProtocol == nil { if portSpec.AppProtocol == nil {
protocol := "http" protocol := schemeHTTP
if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, "https") { if portSpec.Port == 443 || strings.HasPrefix(portSpec.Name, schemeHTTPS) {
protocol = "https" protocol = schemeHTTPS
} }
return protocol, nil return protocol, nil
} }
switch ap := *portSpec.AppProtocol; ap { switch ap := *portSpec.AppProtocol; ap {
case appProtocolH2C: case appProtocolH2C:
return "h2c", nil return schemeH2C, nil
case appProtocolWS: case appProtocolHTTP, appProtocolWS:
return "http", nil return schemeHTTP, nil
case appProtocolWSS: case appProtocolHTTPS, appProtocolWSS:
return "https", nil return schemeHTTPS, nil
default: default:
return "", fmt.Errorf("unsupported application protocol %s", ap) return "", fmt.Errorf("unsupported application protocol %s", ap)
} }

View file

@ -50,9 +50,15 @@ const (
kindTLSRoute = "TLSRoute" kindTLSRoute = "TLSRoute"
kindService = "Service" kindService = "Service"
appProtocolHTTP = "http"
appProtocolHTTPS = "https"
appProtocolH2C = "kubernetes.io/h2c" appProtocolH2C = "kubernetes.io/h2c"
appProtocolWS = "kubernetes.io/ws" appProtocolWS = "kubernetes.io/ws"
appProtocolWSS = "kubernetes.io/wss" appProtocolWSS = "kubernetes.io/wss"
schemeHTTP = "http"
schemeHTTPS = "https"
schemeH2C = "h2c"
) )
// Provider holds configurations of the provider. // Provider holds configurations of the provider.