Skip to content

Commit c83a205

Browse files
committed
Legacy support
Signed-off-by: David Kwon <dakwon@redhat.com>
1 parent c25db9c commit c83a205

File tree

4 files changed

+895
-64
lines changed

4 files changed

+895
-64
lines changed

controllers/devworkspace/solver/che_routing.go

Lines changed: 76 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -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

374390
func 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+
384435
func 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-
661699
func 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

783813
func determineEndpointScheme(e dwo.Endpoint) string {

0 commit comments

Comments
 (0)