@@ -17,7 +17,6 @@ import (
1717 "fmt"
1818 "path"
1919 "regexp"
20- "strconv"
2120 "strings"
2221
2322 dw "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
@@ -282,17 +281,25 @@ func (c *CheRoutingSolver) cheExposedEndpoints(cheCluster *chev2.CheCluster, wor
282281 return map [string ]dwo.ExposedEndpointList {}, false , nil
283282 }
284283
284+ useLegacyRouting := false
285285 username , err := getNormalizedUsername (c .client , routingObj .Services [0 ].Namespace )
286286 if err != nil {
287- return map [ string ]dwo. ExposedEndpointList {}, false , err
287+ useLegacyRouting = true
288288 }
289289
290290 dwName , err := getNormalizedWkspName (c .client , routingObj .Services [0 ].Namespace , routingObj .Services [0 ].ObjectMeta .OwnerReferences [0 ].Name )
291291 if err != nil {
292- return map [ string ]dwo. ExposedEndpointList {}, false , err
292+ useLegacyRouting = true
293293 }
294294
295- publicURLPrefix := getPublicURLPrefixForEndpoint (dwName , username , endpoint )
295+ var endpointStrategy EndpointStrategy
296+ if useLegacyRouting {
297+ endpointStrategy = Legacy {workspaceID : workspaceID , componentName : component }
298+ } else {
299+ endpointStrategy = UsernameWkspName {username : username , workspaceName : dwName }
300+ }
301+
302+ publicURLPrefix := getPublicURLPrefixForEndpoint (endpoint , endpointStrategy )
296303 endpointURL = path .Join (gatewayHost , publicURLPrefix , endpoint .Path )
297304 }
298305
@@ -342,28 +349,37 @@ func (c *CheRoutingSolver) getGatewayConfigsAndFillRoutingObjects(cheCluster *ch
342349 }
343350
344351 configs := make ([]corev1.ConfigMap , 0 )
352+
353+ useLegacyRouting := false
345354 username , err := getNormalizedUsername (c .client , routing .Namespace )
346355 if err != nil {
347- return nil , err
356+ useLegacyRouting = true
348357 }
349358
350359 dwName , err := getNormalizedWkspName (c .client , routing .Namespace , routing .Name )
351360 if err != nil {
352- return nil , err
361+ useLegacyRouting = true
362+ }
363+
364+ var endpointStrategy EndpointStrategy
365+ if useLegacyRouting {
366+ endpointStrategy = Legacy {workspaceID : workspaceID }
367+ } else {
368+ endpointStrategy = UsernameWkspName {username : username , workspaceName : dwName }
353369 }
354370
355371 // first do routing from main che-gateway into workspace service
356- if mainWsRouteConfig , err := provisionMainWorkspaceRoute (cheCluster , routing , username , dwName , cmLabels ); err != nil {
372+ if mainWsRouteConfig , err := provisionMainWorkspaceRoute (cheCluster , routing , cmLabels , endpointStrategy ); err != nil {
357373 return nil , err
358374 } else {
359375 configs = append (configs , * mainWsRouteConfig )
360376 }
361377
362378 // then expose the endpoints
363- if infraExposer , err := c .getInfraSpecificExposer (cheCluster , routing , objs , username , dwName ); err != nil {
379+ if infraExposer , err := c .getInfraSpecificExposer (cheCluster , routing , objs , endpointStrategy ); err != nil {
364380 return nil , err
365381 } else {
366- if workspaceConfig := exposeAllEndpoints (cheCluster , routing , objs , infraExposer ); workspaceConfig != nil {
382+ if workspaceConfig := exposeAllEndpoints (cheCluster , routing , objs , infraExposer , endpointStrategy ); workspaceConfig != nil {
367383 configs = append (configs , * workspaceConfig )
368384 }
369385 }
@@ -372,6 +388,19 @@ func (c *CheRoutingSolver) getGatewayConfigsAndFillRoutingObjects(cheCluster *ch
372388}
373389
374390func getNormalizedUsername (c client.Client , namespace string ) (string , error ) {
391+ username , err := getUsernameFromNamespace (c , namespace )
392+
393+ if err != nil {
394+ username , err = getUsernameFromSecret (c , namespace )
395+ }
396+
397+ if err != nil {
398+ return "" , err
399+ }
400+ return normalize (username ), nil
401+ }
402+
403+ func getUsernameFromSecret (c client.Client , namespace string ) (string , error ) {
375404 secret := & corev1.Secret {}
376405 err := c .Get (context .TODO (), client.ObjectKey {Name : "user-profile" , Namespace : namespace }, secret )
377406 if err != nil {
@@ -381,6 +410,28 @@ func getNormalizedUsername(c client.Client, namespace string) (string, error) {
381410 return normalize (username ), nil
382411}
383412
413+ func getUsernameFromNamespace (c client.Client , namespace string ) (string , error ) {
414+ nsInfo := & corev1.Namespace {}
415+ err := c .Get (context .TODO (), client.ObjectKey {Name : namespace }, nsInfo )
416+ if err != nil {
417+ return "" , err
418+ }
419+
420+ notFoundError := fmt .Errorf ("username not found in namespace %s" , namespace )
421+
422+ if nsInfo .GetAnnotations () == nil {
423+ return "" , notFoundError
424+ }
425+
426+ username , exists := nsInfo .GetAnnotations ()["che.eclipse.org/username" ]
427+
428+ if exists {
429+ return username , nil
430+ }
431+
432+ return "" , notFoundError
433+ }
434+
384435func getNormalizedWkspName (c client.Client , namespace string , routingName string ) (string , error ) {
385436 routing := & dwo.DevWorkspaceRouting {}
386437 err := c .Get (context .TODO (), client.ObjectKey {Name : routingName , Namespace : namespace }, routing )
@@ -400,14 +451,14 @@ func normalize(username string) string {
400451 return r3 .ReplaceAllString (result , "" ) // trim dashes at beginning/end
401452}
402453
403- func (c * CheRoutingSolver ) getInfraSpecificExposer (cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting , objs * solvers.RoutingObjects , username string , dwName string ) (func (info * EndpointInfo ), error ) {
454+ func (c * CheRoutingSolver ) getInfraSpecificExposer (cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting , objs * solvers.RoutingObjects , endpointStrategy EndpointStrategy ) (func (info * EndpointInfo ), error ) {
404455 if infrastructure .IsOpenShift () {
405456 exposer := & RouteExposer {}
406457 if err := exposer .initFrom (context .TODO (), c .client , cheCluster , routing ); err != nil {
407458 return nil , err
408459 }
409460 return func (info * EndpointInfo ) {
410- route := exposer .getRouteForService (info , username , dwName )
461+ route := exposer .getRouteForService (info , endpointStrategy )
411462 objs .Routes = append (objs .Routes , route )
412463 }, nil
413464 } else {
@@ -416,7 +467,7 @@ func (c *CheRoutingSolver) getInfraSpecificExposer(cheCluster *chev2.CheCluster,
416467 return nil , err
417468 }
418469 return func (info * EndpointInfo ) {
419- ingress := exposer .getIngressForService (info , username , dwName )
470+ ingress := exposer .getIngressForService (info , endpointStrategy )
420471 objs .Ingresses = append (objs .Ingresses , ingress )
421472 }, nil
422473 }
@@ -432,7 +483,7 @@ func getCommonService(objs *solvers.RoutingObjects, dwId string) *corev1.Service
432483 return nil
433484}
434485
435- func exposeAllEndpoints (cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting , objs * solvers.RoutingObjects , ingressExpose func (* EndpointInfo )) * corev1.ConfigMap {
486+ func exposeAllEndpoints (cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting , objs * solvers.RoutingObjects , ingressExpose func (* EndpointInfo ), endpointStrategy EndpointStrategy ) * corev1.ConfigMap {
436487 wsRouteConfig := gateway .CreateEmptyTraefikConfig ()
437488
438489 commonService := getCommonService (objs , routing .Spec .DevWorkspaceId )
@@ -463,7 +514,7 @@ func exposeAllEndpoints(cheCluster *chev2.CheCluster, routing *dwo.DevWorkspaceR
463514 }
464515
465516 if e .Attributes .GetString (urlRewriteSupportedEndpointAttributeName , nil ) == "true" {
466- addEndpointToTraefikConfig (componentName , e , wsRouteConfig , cheCluster , routing )
517+ addEndpointToTraefikConfig (componentName , e , wsRouteConfig , cheCluster , routing , endpointStrategy )
467518 } else {
468519 ingressExpose (& EndpointInfo {
469520 order : order ,
@@ -524,16 +575,16 @@ func containPort(service *corev1.Service, port int32) bool {
524575 return false
525576}
526577
527- func provisionMainWorkspaceRoute (cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting , username string , dwName string , cmLabels map [string ]string ) (* corev1.ConfigMap , error ) {
578+ func provisionMainWorkspaceRoute (cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting , cmLabels map [string ]string , endpointStrategy EndpointStrategy ) (* corev1.ConfigMap , error ) {
528579 dwId := routing .Spec .DevWorkspaceId
529580 dwNamespace := routing .Namespace
530581
531582 cfg := gateway .CreateCommonTraefikConfig (
532583 dwId ,
533- fmt .Sprintf ("PathPrefix(`/%s/%s `)" , username , dwName ),
584+ fmt .Sprintf ("PathPrefix(`%s `)" , endpointStrategy . getMainWorkspacePathPrefix () ),
534585 100 ,
535586 getServiceURL (wsGatewayPort , dwId , dwNamespace ),
536- []string {fmt . Sprintf ( "/%s/%s" , username , dwName )})
587+ []string {endpointStrategy . getMainWorkspacePathPrefix ( )})
537588
538589 if cheCluster .IsAccessTokenConfigured () {
539590 cfg .AddAuthHeaderRewrite (dwId )
@@ -545,7 +596,7 @@ func provisionMainWorkspaceRoute(cheCluster *chev2.CheCluster, routing *dwo.DevW
545596 add5XXErrorHandling (cfg , dwId )
546597
547598 // make '/healthz' path of main endpoints reachable from outside
548- routeForHealthzEndpoint (cfg , username , dwName , dwId , routing .Spec .Endpoints )
599+ routeForHealthzEndpoint (cfg , dwId , routing .Spec .Endpoints , endpointStrategy )
549600
550601 if contents , err := yaml .Marshal (cfg ); err != nil {
551602 return nil , err
@@ -591,18 +642,18 @@ func add5XXErrorHandling(cfg *gateway.TraefikConfig, dwId string) {
591642}
592643
593644// makes '/healthz' path of main endpoints reachable from the outside
594- func routeForHealthzEndpoint (cfg * gateway.TraefikConfig , username string , dwName string , dwId string , endpoints map [string ]dwo.EndpointList ) {
645+ func routeForHealthzEndpoint (cfg * gateway.TraefikConfig , dwId string , endpoints map [string ]dwo.EndpointList , endpointStrategy EndpointStrategy ) {
595646 for componentName , endpoints := range endpoints {
596647 for _ , e := range endpoints {
597648 if e .Attributes .GetString (string (dwo .TypeEndpointAttribute ), nil ) == string (dwo .MainEndpointType ) {
598649 middlewares := []string {dwId + gateway .StripPrefixMiddlewareSuffix }
599650 if infrastructure .IsOpenShift () {
600651 middlewares = append (middlewares , dwId + gateway .HeaderRewriteMiddlewareSuffix )
601652 }
602- routeName , endpointPath := createEndpointPath (& e , componentName )
653+ routeName , endpointPath := endpointStrategy . getEndpointPath (& e , componentName )
603654 routerName := fmt .Sprintf ("%s-%s-healthz" , dwId , routeName )
604655 cfg .HTTP .Routers [routerName ] = & gateway.TraefikConfigRouter {
605- Rule : fmt .Sprintf ("Path(`/ %s/%s%s/ healthz`)" , username , dwName , endpointPath ),
656+ Rule : fmt .Sprintf ("Path(`%s/healthz`)" , endpointStrategy . getEndpointPathPrefix ( endpointPath ) ),
606657 Service : dwId ,
607658 Middlewares : middlewares ,
608659 Priority : 101 ,
@@ -612,8 +663,8 @@ func routeForHealthzEndpoint(cfg *gateway.TraefikConfig, username string, dwName
612663 }
613664}
614665
615- func addEndpointToTraefikConfig (componentName string , e dwo.Endpoint , cfg * gateway.TraefikConfig , cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting ) {
616- routeName , prefix := createEndpointPath (& e , componentName )
666+ func addEndpointToTraefikConfig (componentName string , e dwo.Endpoint , cfg * gateway.TraefikConfig , cheCluster * chev2.CheCluster , routing * dwo.DevWorkspaceRouting , endpointStrategy EndpointStrategy ) {
667+ routeName , prefix := endpointStrategy . getEndpointPath (& e , componentName )
617668 rulePrefix := fmt .Sprintf ("PathPrefix(`%s`)" , prefix )
618669
619670 // skip if exact same route is already exposed
@@ -645,19 +696,6 @@ func addEndpointToTraefikConfig(componentName string, e dwo.Endpoint, cfg *gatew
645696 }
646697}
647698
648- func createEndpointPath (e * dwo.Endpoint , componentName string ) (routeName string , path string ) {
649- if e .Attributes .GetString (uniqueEndpointAttributeName , nil ) == "true" {
650- // if endpoint is unique, we're exposing on /componentName/<endpoint-name>
651- routeName = e .Name
652- } else {
653- // if endpoint is NOT unique, we're exposing on /componentName/<port-number>
654- routeName = strconv .Itoa (e .TargetPort )
655- }
656- path = fmt .Sprintf ("/%s" , routeName )
657-
658- return routeName , path
659- }
660-
661699func findServiceForPort (port int32 , objs * solvers.RoutingObjects ) * corev1.Service {
662700 for i := range objs .Services {
663701 svc := & objs .Services [i ]
@@ -764,20 +802,12 @@ func getServiceURL(port int32, workspaceID string, workspaceNamespace string) st
764802 return fmt .Sprintf ("http://%s.%s.svc:%d" , common .ServiceName (workspaceID ), workspaceNamespace , port )
765803}
766804
767- func getPublicURLPrefixForEndpoint (dwName string , username string , endpoint dwo.Endpoint ) string {
805+ func getPublicURLPrefixForEndpoint (endpoint dwo.Endpoint , endpointStrategy EndpointStrategy ) string {
768806 endpointName := ""
769807 if endpoint .Attributes .GetString (uniqueEndpointAttributeName , nil ) == "true" {
770808 endpointName = endpoint .Name
771809 }
772-
773- return getPublicURLPrefix (dwName , username , int32 (endpoint .TargetPort ), endpointName )
774- }
775-
776- func getPublicURLPrefix (dwName string , username string , port int32 , uniqueEndpointName string ) string {
777- if uniqueEndpointName == "" {
778- return fmt .Sprintf (endpointURLPrefixPattern , username , dwName , port )
779- }
780- return fmt .Sprintf (uniqueEndpointURLPrefixPattern , username , dwName , uniqueEndpointName )
810+ return endpointStrategy .getPublicURLPrefix (int32 (endpoint .TargetPort ), endpointName )
781811}
782812
783813func determineEndpointScheme (e dwo.Endpoint ) string {
0 commit comments