Skip to content
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
71 changes: 70 additions & 1 deletion build/scripts/minikube-tests/test-operator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,75 @@ runTest() {
yq -riSY '.spec.template.spec.containers[0].image = "'${OPERATOR_IMAGE}'"' "${CURRENT_OPERATOR_VERSION_TEMPLATE_PATH}/che-operator/kubernetes/operator.yaml"
yq -riSY '.spec.template.spec.containers[0].imagePullPolicy = "IfNotPresent"' "${CURRENT_OPERATOR_VERSION_TEMPLATE_PATH}/che-operator/kubernetes/operator.yaml"

cat > /tmp/patch.yaml <<EOF
apiVersion: org.eclipse.che/v2
spec:
components:
pluginRegistry:
openVSXURL: https://open-vsx.org
deployment:
containers:
- resources:
request:
cpu: '20m'
limits:
cpu: '20m'
devfileRegistry:
deployment:
containers:
- resources:
request:
cpu: '20m'
limits:
cpu: '20m'
cheServer:
deployment:
containers:
- resources:
limits:
cpu: '400m'
request:
cpu: '400m'
image: 'quay.io/dkwon17/che-server:user-profile-che-operator'
dashboard:
deployment:
containers:
- resources:
request:
cpu: '40m'
limits:
cpu: '40m'
networking:
auth:
gateway:
deployment:
containers:
- name: gateway
resources:
request:
cpu: '20m'
limits:
cpu: '20m'
- name: configbump
resources:
request:
cpu: '20m'
limits:
cpu: '20m'
- name: oauth-proxy
resources:
request:
cpu: '20m'
limits:
cpu: '20m'
- name: kube-rbac-proxy
resources:
request:
cpu: '20m'
limits:
cpu: '20m'
EOF

chectl server:deploy \
--batch \
--platform minikube \
Expand All @@ -38,7 +107,7 @@ runTest() {
--templates "${CURRENT_OPERATOR_VERSION_TEMPLATE_PATH}" \
--k8spodwaittimeout=120000 \
--k8spodreadytimeout=120000 \
--che-operator-cr-patch-yaml "${OPERATOR_REPO}/build/scripts/minikube-tests/minikube-checluster-patch.yaml"
--che-operator-cr-patch-yaml /tmp/patch.yaml

make wait-devworkspace-running NAMESPACE="devworkspace-controller" VERBOSE=1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ metadata:
operators.operatorframework.io/project_layout: go.kubebuilder.io/v3
repository: https://github.com/eclipse-che/che-operator
support: Eclipse Foundation
name: eclipse-che.v7.66.0-791.next
name: eclipse-che.v7.66.0-792.next
namespace: placeholder
spec:
apiservicedefinitions: {}
Expand Down Expand Up @@ -713,6 +713,7 @@ spec:
- create
- watch
- get
- update
- delete
- apiGroups:
- apiextensions.k8s.io
Expand Down Expand Up @@ -1243,7 +1244,7 @@ spec:
minKubeVersion: 1.19.0
provider:
name: Eclipse Foundation
version: 7.66.0-791.next
version: 7.66.0-792.next
webhookdefinitions:
- admissionReviewVersions:
- v1
Expand Down
1 change: 1 addition & 0 deletions config/rbac/cluster_role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ rules:
- create
- watch
- get
- update
- delete
- apiGroups:
- apiextensions.k8s.io
Expand Down
85 changes: 67 additions & 18 deletions controllers/devworkspace/solver/che_routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"context"
"fmt"
"path"
"regexp"
"strconv"
"strings"

Expand Down Expand Up @@ -281,7 +282,17 @@ func (c *CheRoutingSolver) cheExposedEndpoints(cheCluster *chev2.CheCluster, wor
return map[string]dwo.ExposedEndpointList{}, false, nil
}

publicURLPrefix := getPublicURLPrefixForEndpoint(workspaceID, component, endpoint)
username, err := getNormalizedUsername(c.client, routingObj.Services[0].Namespace)
if err != nil {
return map[string]dwo.ExposedEndpointList{}, false, err
}

dwName, err := getNormalizedWkspName(c.client, routingObj.Services[0].Namespace, routingObj.Services[0].ObjectMeta.OwnerReferences[0].Name)
if err != nil {
return map[string]dwo.ExposedEndpointList{}, false, err
}

publicURLPrefix := getPublicURLPrefixForEndpoint(dwName, username, endpoint)
endpointURL = path.Join(gatewayHost, publicURLPrefix, endpoint.Path)
}

Expand Down Expand Up @@ -331,16 +342,25 @@ func (c *CheRoutingSolver) getGatewayConfigsAndFillRoutingObjects(cheCluster *ch
}

configs := make([]corev1.ConfigMap, 0)
username, err := getNormalizedUsername(c.client, routing.Namespace)
if err != nil {
return nil, err
}

dwName, err := getNormalizedWkspName(c.client, routing.Namespace, routing.Name)
if err != nil {
return nil, err
}

// first do routing from main che-gateway into workspace service
if mainWsRouteConfig, err := provisionMainWorkspaceRoute(cheCluster, routing, cmLabels); err != nil {
if mainWsRouteConfig, err := provisionMainWorkspaceRoute(cheCluster, routing, username, dwName, cmLabels); err != nil {
return nil, err
} else {
configs = append(configs, *mainWsRouteConfig)
}

// then expose the endpoints
if infraExposer, err := c.getInfraSpecificExposer(cheCluster, routing, objs); err != nil {
if infraExposer, err := c.getInfraSpecificExposer(cheCluster, routing, objs, username, dwName); err != nil {
return nil, err
} else {
if workspaceConfig := exposeAllEndpoints(cheCluster, routing, objs, infraExposer); workspaceConfig != nil {
Expand All @@ -351,14 +371,43 @@ func (c *CheRoutingSolver) getGatewayConfigsAndFillRoutingObjects(cheCluster *ch
return configs, nil
}

func (c *CheRoutingSolver) getInfraSpecificExposer(cheCluster *chev2.CheCluster, routing *dwo.DevWorkspaceRouting, objs *solvers.RoutingObjects) (func(info *EndpointInfo), error) {
func getNormalizedUsername(c client.Client, namespace string) (string, error) {
secret := &corev1.Secret{}
err := c.Get(context.TODO(), client.ObjectKey{Name: "user-profile", Namespace: namespace}, secret)
if err != nil {
return "", err
}
username := string(secret.Data["name"])
return normalize(username), nil
}

func getNormalizedWkspName(c client.Client, namespace string, routingName string) (string, error) {
routing := &dwo.DevWorkspaceRouting{}
err := c.Get(context.TODO(), client.ObjectKey{Name: routingName, Namespace: namespace}, routing)
if err != nil {
return "", err
}
return normalize(routing.ObjectMeta.OwnerReferences[0].Name), nil
}

func normalize(username string) string {
r1 := regexp.MustCompile(`[^-a-zA-Z0-9]`)
r2 := regexp.MustCompile(`-+`)
r3 := regexp.MustCompile(`^-|-$`)

result := r1.ReplaceAllString(username, "-") // replace invalid chars with '-'
result = r2.ReplaceAllString(result, "-") // replace multiple '-' with single ones
return r3.ReplaceAllString(result, "") // trim dashes at beginning/end
}

func (c *CheRoutingSolver) getInfraSpecificExposer(cheCluster *chev2.CheCluster, routing *dwo.DevWorkspaceRouting, objs *solvers.RoutingObjects, username string, dwName string) (func(info *EndpointInfo), error) {
if infrastructure.IsOpenShift() {
exposer := &RouteExposer{}
if err := exposer.initFrom(context.TODO(), c.client, cheCluster, routing); err != nil {
return nil, err
}
return func(info *EndpointInfo) {
route := exposer.getRouteForService(info)
route := exposer.getRouteForService(info, username, dwName)
objs.Routes = append(objs.Routes, route)
}, nil
} else {
Expand All @@ -367,7 +416,7 @@ func (c *CheRoutingSolver) getInfraSpecificExposer(cheCluster *chev2.CheCluster,
return nil, err
}
return func(info *EndpointInfo) {
ingress := exposer.getIngressForService(info)
ingress := exposer.getIngressForService(info, username, dwName)
objs.Ingresses = append(objs.Ingresses, ingress)
}, nil
}
Expand Down Expand Up @@ -475,16 +524,16 @@ func containPort(service *corev1.Service, port int32) bool {
return false
}

func provisionMainWorkspaceRoute(cheCluster *chev2.CheCluster, routing *dwo.DevWorkspaceRouting, cmLabels map[string]string) (*corev1.ConfigMap, error) {
func provisionMainWorkspaceRoute(cheCluster *chev2.CheCluster, routing *dwo.DevWorkspaceRouting, username string, dwName string, cmLabels map[string]string) (*corev1.ConfigMap, error) {
dwId := routing.Spec.DevWorkspaceId
dwNamespace := routing.Namespace

cfg := gateway.CreateCommonTraefikConfig(
dwId,
fmt.Sprintf("PathPrefix(`/%s`)", dwId),
fmt.Sprintf("PathPrefix(`/%s/%s`)", username, dwName),
100,
getServiceURL(wsGatewayPort, dwId, dwNamespace),
[]string{"/" + dwId})
[]string{fmt.Sprintf("/%s/%s", username, dwName)})

if cheCluster.IsAccessTokenConfigured() {
cfg.AddAuthHeaderRewrite(dwId)
Expand All @@ -496,7 +545,7 @@ func provisionMainWorkspaceRoute(cheCluster *chev2.CheCluster, routing *dwo.DevW
add5XXErrorHandling(cfg, dwId)

// make '/healthz' path of main endpoints reachable from outside
routeForHealthzEndpoint(cfg, dwId, routing.Spec.Endpoints)
routeForHealthzEndpoint(cfg, username, dwName, dwId, routing.Spec.Endpoints)

if contents, err := yaml.Marshal(cfg); err != nil {
return nil, err
Expand Down Expand Up @@ -542,7 +591,7 @@ func add5XXErrorHandling(cfg *gateway.TraefikConfig, dwId string) {
}

// makes '/healthz' path of main endpoints reachable from the outside
func routeForHealthzEndpoint(cfg *gateway.TraefikConfig, dwId string, endpoints map[string]dwo.EndpointList) {
func routeForHealthzEndpoint(cfg *gateway.TraefikConfig, username string, dwName string, dwId string, endpoints map[string]dwo.EndpointList) {
for componentName, endpoints := range endpoints {
for _, e := range endpoints {
if e.Attributes.GetString(string(dwo.TypeEndpointAttribute), nil) == string(dwo.MainEndpointType) {
Expand All @@ -553,7 +602,7 @@ func routeForHealthzEndpoint(cfg *gateway.TraefikConfig, dwId string, endpoints
routeName, endpointPath := createEndpointPath(&e, componentName)
routerName := fmt.Sprintf("%s-%s-healthz", dwId, routeName)
cfg.HTTP.Routers[routerName] = &gateway.TraefikConfigRouter{
Rule: fmt.Sprintf("Path(`/%s%s/healthz`)", dwId, endpointPath),
Rule: fmt.Sprintf("Path(`/%s/%s%s/healthz`)", username, dwName, endpointPath),
Service: dwId,
Middlewares: middlewares,
Priority: 101,
Expand Down Expand Up @@ -604,7 +653,7 @@ func createEndpointPath(e *dwo.Endpoint, componentName string) (routeName string
// if endpoint is NOT unique, we're exposing on /componentName/<port-number>
routeName = strconv.Itoa(e.TargetPort)
}
path = fmt.Sprintf("/%s/%s", componentName, routeName)
path = fmt.Sprintf("/%s", routeName)

return routeName, path
}
Expand Down Expand Up @@ -715,20 +764,20 @@ func getServiceURL(port int32, workspaceID string, workspaceNamespace string) st
return fmt.Sprintf("http://%s.%s.svc:%d", common.ServiceName(workspaceID), workspaceNamespace, port)
}

func getPublicURLPrefixForEndpoint(workspaceID string, machineName string, endpoint dwo.Endpoint) string {
func getPublicURLPrefixForEndpoint(dwName string, username string, endpoint dwo.Endpoint) string {
endpointName := ""
if endpoint.Attributes.GetString(uniqueEndpointAttributeName, nil) == "true" {
endpointName = endpoint.Name
}

return getPublicURLPrefix(workspaceID, machineName, int32(endpoint.TargetPort), endpointName)
return getPublicURLPrefix(dwName, username, int32(endpoint.TargetPort), endpointName)
}

func getPublicURLPrefix(workspaceID string, machineName string, port int32, uniqueEndpointName string) string {
func getPublicURLPrefix(dwName string, username string, port int32, uniqueEndpointName string) string {
if uniqueEndpointName == "" {
return fmt.Sprintf(endpointURLPrefixPattern, workspaceID, machineName, port)
return fmt.Sprintf(endpointURLPrefixPattern, username, dwName, port)
}
return fmt.Sprintf(uniqueEndpointURLPrefixPattern, workspaceID, machineName, uniqueEndpointName)
return fmt.Sprintf(uniqueEndpointURLPrefixPattern, username, dwName, uniqueEndpointName)
}

func determineEndpointScheme(e dwo.Endpoint) string {
Expand Down
Loading