@@ -24,7 +24,7 @@ import (
2424 "strconv"
2525
2626 "github.com/pkg/errors"
27- v1 "k8s.io/api/core/v1"
27+ corev1 "k8s.io/api/core/v1"
2828 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2929 "k8s.io/apimachinery/pkg/types"
3030 "k8s.io/apimachinery/pkg/util/intstr"
@@ -70,9 +70,11 @@ func (t *Translator) translateHTTPRule(tctx *provider.TranslateContext, ar *apiv
7070 return nil , err
7171 }
7272
73+ var enableWebsocket * bool
7374 service := t .buildService (ar , rule , ruleIndex )
74- t .buildRoute (ar , service , rule , plugins , timeout , vars )
75- t .buildUpstream (tctx , service , ar , rule , ruleIndex )
75+ // should build upstream before route because route needs to know the enableWebsocket flag
76+ t .buildUpstream (tctx , service , ar , rule , ruleIndex , & enableWebsocket )
77+ t .buildRoute (ar , service , rule , plugins , timeout , vars , & enableWebsocket )
7678
7779 return service , nil
7880}
@@ -139,7 +141,7 @@ func (t *Translator) loadRoutePlugins(tctx *provider.TranslateContext, ar *apiv2
139141 }
140142}
141143
142- func (t * Translator ) buildPluginConfig (plugin apiv2.ApisixRoutePlugin , namespace string , secrets map [types.NamespacedName ]* v1 .Secret ) map [string ]any {
144+ func (t * Translator ) buildPluginConfig (plugin apiv2.ApisixRoutePlugin , namespace string , secrets map [types.NamespacedName ]* corev1 .Secret ) map [string ]any {
143145 config := make (map [string ]any )
144146 if len (plugin .Config .Raw ) > 0 {
145147 if err := json .Unmarshal (plugin .Config .Raw , & config ); err != nil {
@@ -179,13 +181,16 @@ func (t *Translator) addAuthenticationPlugins(rule apiv2.ApisixRouteHTTP, plugin
179181 }
180182}
181183
182- func (t * Translator ) buildRoute (ar * apiv2.ApisixRoute , service * adc.Service , rule apiv2.ApisixRouteHTTP , plugins adc.Plugins , timeout * adc.Timeout , vars adc.Vars ) {
184+ func (t * Translator ) buildRoute (ar * apiv2.ApisixRoute , service * adc.Service , rule apiv2.ApisixRouteHTTP , plugins adc.Plugins , timeout * adc.Timeout , vars adc.Vars , enableWebsocket * * bool ) {
183185 route := adc .NewDefaultRoute ()
184186 route .Name = adc .ComposeRouteName (ar .Namespace , ar .Name , rule .Name )
185187 route .ID = id .GenID (route .Name )
186188 route .Desc = "Created by apisix-ingress-controller, DO NOT modify it manually"
187189 route .Labels = label .GenLabel (ar )
188- route .EnableWebsocket = ptr .To (rule .Websocket )
190+ route .EnableWebsocket = rule .Websocket
191+ if route .EnableWebsocket == nil && * enableWebsocket != nil {
192+ route .EnableWebsocket = * enableWebsocket
193+ }
189194 route .FilterFunc = rule .Match .FilterFunc
190195 route .Hosts = rule .Match .Hosts
191196 route .Methods = rule .Match .Methods
@@ -202,7 +207,7 @@ func (t *Translator) buildRoute(ar *apiv2.ApisixRoute, service *adc.Service, rul
202207 service .Routes = []* adc.Route {route }
203208}
204209
205- func (t * Translator ) buildUpstream (tctx * provider.TranslateContext , service * adc.Service , ar * apiv2.ApisixRoute , rule apiv2.ApisixRouteHTTP , ruleIndex int ) {
210+ func (t * Translator ) buildUpstream (tctx * provider.TranslateContext , service * adc.Service , ar * apiv2.ApisixRoute , rule apiv2.ApisixRouteHTTP , ruleIndex int , enableWebsocket * * bool ) {
206211 var (
207212 upstreams = make ([]* adc.Upstream , 0 )
208213 weightedUpstreams = make ([]adc.TrafficSplitConfigRuleWeightedUpstream , 0 )
@@ -211,7 +216,7 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
211216 for backendIndex , backend := range rule .Backends {
212217 // try to get the apisixupstream with the same name as the backend service to be upstream config.
213218 // err is ignored because it does not care about the externalNodes of the apisixupstream.
214- upstream , err := t .translateApisixRouteHTTPBackend (tctx , ar , backend )
219+ upstream , err := t .translateApisixRouteHTTPBackend (tctx , ar , backend , enableWebsocket )
215220 if err != nil {
216221 t .Log .Error (err , "failed to translate ApisixRoute backend" , "backend" , backend )
217222 continue
@@ -312,7 +317,7 @@ func (t *Translator) buildService(ar *apiv2.ApisixRoute, rule apiv2.ApisixRouteH
312317 return service
313318}
314319
315- func getPortFromService (svc * v1 .Service , backendSvcPort intstr.IntOrString ) (int32 , error ) {
320+ func getPortFromService (svc * corev1 .Service , backendSvcPort intstr.IntOrString ) (int32 , error ) {
316321 var port int32
317322 if backendSvcPort .Type == intstr .Int {
318323 port = int32 (backendSvcPort .IntValue ())
@@ -332,7 +337,31 @@ func getPortFromService(svc *v1.Service, backendSvcPort intstr.IntOrString) (int
332337 return port , nil
333338}
334339
335- func (t * Translator ) translateApisixRouteHTTPBackend (tctx * provider.TranslateContext , ar * apiv2.ApisixRoute , backend apiv2.ApisixRouteHTTPBackend ) (* adc.Upstream , error ) {
340+ func findMatchingServicePort (svc * corev1.Service , backendSvcPort intstr.IntOrString ) (* corev1.ServicePort , error ) {
341+ var servicePort * corev1.ServicePort
342+ var portNumber int32 = - 1
343+ var servicePortName string
344+ switch backendSvcPort .Type {
345+ case intstr .Int :
346+ portNumber = backendSvcPort .IntVal
347+ case intstr .String :
348+ servicePortName = backendSvcPort .StrVal
349+ }
350+ for _ , svcPort := range svc .Spec .Ports {
351+ p := svcPort
352+ if p .Port == portNumber || (p .Name != "" && p .Name == servicePortName ) {
353+ servicePort = & p
354+ break
355+ }
356+ }
357+ if servicePort == nil {
358+ return nil , errors .Errorf ("service port %s not found in service %s" , backendSvcPort .String (), svc .Name )
359+ }
360+
361+ return servicePort , nil
362+ }
363+
364+ func (t * Translator ) translateApisixRouteHTTPBackend (tctx * provider.TranslateContext , ar * apiv2.ApisixRoute , backend apiv2.ApisixRouteHTTPBackend , enableWebsocket * * bool ) (* adc.Upstream , error ) {
336365 auNN := types.NamespacedName {
337366 Namespace : ar .Namespace ,
338367 Name : backend .ServiceName ,
@@ -354,50 +383,57 @@ func (t *Translator) translateApisixRouteHTTPBackend(tctx *provider.TranslateCon
354383 upstream = u
355384 }
356385 var (
357- err error
358- nodes adc.UpstreamNodes
386+ err error
387+ nodes adc.UpstreamNodes
388+ protocol string
359389 )
360390 if backend .ResolveGranularity == apiv2 .ResolveGranularityService {
361- nodes , err = t .translateApisixRouteBackendResolveGranularityService (tctx , auNN , backend )
391+ nodes , protocol , err = t .translateApisixRouteBackendResolveGranularityService (tctx , auNN , backend )
362392 } else {
363- nodes , err = t .translateApisixRouteBackendResolveGranularityEndpoint (tctx , auNN , backend )
393+ nodes , protocol , err = t .translateApisixRouteBackendResolveGranularityEndpoint (tctx , auNN , backend )
364394 }
365395 if err != nil {
366396 return nil , err
367397 }
368398 upstream .Nodes = nodes
399+ if upstream .Scheme == "" {
400+ upstream .Scheme = appProtocolToUpstreamScheme (protocol )
401+ }
402+ if protocol == internaltypes .AppProtocolWS || protocol == internaltypes .AppProtocolWSS {
403+ * enableWebsocket = ptr .To (true )
404+ }
369405 if backend .Weight != nil {
370406 upstream .Labels ["meta_weight" ] = strconv .FormatInt (int64 (* backend .Weight ), 10 )
371407 }
372408 return upstream , nil
373409}
374410
375- func (t * Translator ) translateApisixRouteBackendResolveGranularityService (tctx * provider.TranslateContext , arNN types.NamespacedName , backend apiv2.ApisixRouteHTTPBackend ) (adc.UpstreamNodes , error ) {
411+ func (t * Translator ) translateApisixRouteBackendResolveGranularityService (tctx * provider.TranslateContext , arNN types.NamespacedName , backend apiv2.ApisixRouteHTTPBackend ) (adc.UpstreamNodes , string , error ) {
376412 serviceNN := types.NamespacedName {
377413 Namespace : arNN .Namespace ,
378414 Name : backend .ServiceName ,
379415 }
380416 svc , ok := tctx .Services [serviceNN ]
381417 if ! ok {
382- return nil , errors .Errorf ("service not found, ApisixRoute: %s, Service: %s" , arNN , serviceNN )
418+ return nil , "" , errors .Errorf ("service not found, ApisixRoute: %s, Service: %s" , arNN , serviceNN )
383419 }
384420 if svc .Spec .ClusterIP == "" {
385- return nil , errors .Errorf ("conflict headless service and backend resolve granularity, ApisixRoute: %s, Service: %s" , arNN , serviceNN )
421+ return nil , "" , errors .Errorf ("conflict headless service and backend resolve granularity, ApisixRoute: %s, Service: %s" , arNN , serviceNN )
386422 }
387- port , err := getPortFromService (svc , backend .ServicePort )
423+ port , err := findMatchingServicePort (svc , backend .ServicePort )
388424 if err != nil {
389- return nil , err
425+ return nil , "" , err
390426 }
391427 return adc.UpstreamNodes {
392428 {
393429 Host : svc .Spec .ClusterIP ,
394- Port : int (port ),
430+ Port : int (port . Port ),
395431 Weight : * cmp .Or (backend .Weight , ptr .To (apiv2 .DefaultWeight )),
396432 },
397- }, nil
433+ }, ptr . Deref ( port . AppProtocol , "" ), nil
398434}
399435
400- func (t * Translator ) translateApisixRouteStreamBackendResolveGranularity (tctx * provider.TranslateContext , arNN types.NamespacedName , backend apiv2.ApisixRouteStreamBackend ) (adc.UpstreamNodes , error ) {
436+ func (t * Translator ) translateApisixRouteStreamBackendResolveGranularity (tctx * provider.TranslateContext , arNN types.NamespacedName , backend apiv2.ApisixRouteStreamBackend ) (adc.UpstreamNodes , string , error ) {
401437 tsBackend := apiv2.ApisixRouteHTTPBackend {
402438 ServiceName : backend .ServiceName ,
403439 ServicePort : backend .ServicePort ,
@@ -411,18 +447,18 @@ func (t *Translator) translateApisixRouteStreamBackendResolveGranularity(tctx *p
411447 }
412448}
413449
414- func (t * Translator ) translateApisixRouteBackendResolveGranularityEndpoint (tctx * provider.TranslateContext , arNN types.NamespacedName , backend apiv2.ApisixRouteHTTPBackend ) (adc.UpstreamNodes , error ) {
450+ func (t * Translator ) translateApisixRouteBackendResolveGranularityEndpoint (tctx * provider.TranslateContext , arNN types.NamespacedName , backend apiv2.ApisixRouteHTTPBackend ) (adc.UpstreamNodes , string , error ) {
415451 serviceNN := types.NamespacedName {
416452 Namespace : arNN .Namespace ,
417453 Name : backend .ServiceName ,
418454 }
419455 svc , ok := tctx .Services [serviceNN ]
420456 if ! ok {
421- return nil , errors .Errorf ("service not found, ApisixRoute: %s, Service: %s" , arNN , serviceNN )
457+ return nil , "" , errors .Errorf ("service not found, ApisixRoute: %s, Service: %s" , arNN , serviceNN )
422458 }
423459 port , err := getPortFromService (svc , backend .ServicePort )
424460 if err != nil {
425- return nil , err
461+ return nil , "" , err
426462 }
427463 weight := int32 (* cmp .Or (backend .Weight , ptr .To (apiv2 .DefaultWeight )))
428464 backendRef := gatewayv1.BackendRef {
@@ -484,7 +520,7 @@ func (t *Translator) translateApisixRouteStreamBackend(tctx *provider.TranslateC
484520 }
485521 upstream = u
486522 }
487- nodes , err := t .translateApisixRouteStreamBackendResolveGranularity (tctx , utils .NamespacedName (ar ), backend )
523+ nodes , _ , err := t .translateApisixRouteStreamBackendResolveGranularity (tctx , utils .NamespacedName (ar ), backend )
488524 if err != nil {
489525 return nil , err
490526 }
0 commit comments