From 5a5538b163c82702048af92e6ff360b9080c93c2 Mon Sep 17 00:00:00 2001 From: Johannes Faltermeier Date: Mon, 17 Jun 2024 10:42:19 +0200 Subject: [PATCH] Add WebView Support #296 (#298) * add ingressHostnamePrefixes to AppDefinition * update ingress rules with additional values from ingressHostnamePrefixes --- CHANGELOG.md | 1 + documentation/LocalCertificates.md | 11 ++++ .../appdefinition/AppDefinitionSpec.java | 9 ++++ .../appdefinition/hub/AppDefinitionHub.java | 9 ++++ .../handler/session/LazySessionHandler.java | 50 ++++++++++++------- 5 files changed, 61 insertions(+), 19 deletions(-) create mode 100644 documentation/LocalCertificates.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 8284f141..05829626 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Extend configuration options for the new landing page for texts and logo file type - Removed terms and conditions - Build the common package as ESM and CJS bundles for extended compatibility +- [common] Add `ingressHostnamePrefixes` list to `AppDefinition.v1beta10` [#298](https://github.com/eclipsesource/theia-cloud/pull/298) | [#57](https://github.com/eclipsesource/theia-cloud-helm/pull/57) ## [0.10.0] - 2024-04-02 diff --git a/documentation/LocalCertificates.md b/documentation/LocalCertificates.md new file mode 100644 index 00000000..a2f82f4a --- /dev/null +++ b/documentation/LocalCertificates.md @@ -0,0 +1,11 @@ +# Installing the self signed CA for local testing + +When testing locally you usually have to accept the self signed certificate in your browser. When working with wildcard certificates however, as used by e.g. the default webview hostnames, you usually will get an error with no way to accept the certificate. + +You may import the self-signed CA in your browser however. You may export the secret to an importable file like this: + +```bash +kubectl get secret theia-cloud-ca-key-pair -n cert-manager -o jsonpath='{.data.tls\.crt}' | base64 --decode > ca.crt +``` + +Then, e.g. in Chrome, got to and Add Authority. diff --git a/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/AppDefinitionSpec.java b/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/AppDefinitionSpec.java index 5b2b10a3..90355360 100644 --- a/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/AppDefinitionSpec.java +++ b/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/AppDefinitionSpec.java @@ -16,6 +16,7 @@ ********************************************************************************/ package org.eclipse.theia.cloud.common.k8s.resource.appdefinition; +import java.util.List; import java.util.Map; import org.eclipse.theia.cloud.common.k8s.resource.appdefinition.hub.AppDefinitionHub; @@ -83,6 +84,9 @@ public class AppDefinitionSpec { @JsonProperty("options") private Map options; + @JsonProperty("ingressHostnamePrefixes") + private List ingressHostnamePrefixes; + /** * Default constructor. */ @@ -110,6 +114,7 @@ public AppDefinitionSpec(AppDefinitionHub fromHub) { this.timeout = fromHub.getTimeoutLimit().orElse(0); this.options = fromHub.getOptions().orElse(null); + this.ingressHostnamePrefixes = fromHub.getIngressHostnamePrefixes().orElse(null); int monitorPort = fromHub.getMonitorPort().orElse(0); if (monitorPort > 0) { @@ -201,6 +206,10 @@ public Map getOptions() { return options; } + public List getIngressHostnamePrefixes() { + return ingressHostnamePrefixes; + } + @Override public String toString() { return "AppDefinitionSpec [name=" + name + ", image=" + image + ", imagePullPolicy=" + imagePullPolicy diff --git a/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/hub/AppDefinitionHub.java b/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/hub/AppDefinitionHub.java index dd41b1b2..24934ac9 100644 --- a/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/hub/AppDefinitionHub.java +++ b/java/common/org.eclipse.theia.cloud.common/src/main/java/org/eclipse/theia/cloud/common/k8s/resource/appdefinition/hub/AppDefinitionHub.java @@ -15,6 +15,7 @@ ********************************************************************************/ package org.eclipse.theia.cloud.common.k8s.resource.appdefinition.hub; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.OptionalInt; @@ -42,6 +43,7 @@ public class AppDefinitionHub { final OptionalInt downlinkLimit;// kilobits per second final OptionalInt uplinkLimit;// kilobits per second final Optional mountPath; + final Optional> ingressHostnamePrefixes; final OptionalInt timeoutLimit; @Deprecated @@ -75,6 +77,7 @@ public AppDefinitionHub(AppDefinition toHub) { this.uplinkLimit = OptionalInt.of(toHub.getSpec().getUplinkLimit()); this.mountPath = Optional.ofNullable(toHub.getSpec().getMountPath()); this.options = Optional.ofNullable(toHub.getSpec().getOptions()); + this.ingressHostnamePrefixes = Optional.ofNullable(toHub.getSpec().getIngressHostnamePrefixes()); this.timeoutLimit = OptionalInt.of(toHub.getSpec().getTimeout()); @@ -126,6 +129,7 @@ public AppDefinitionHub( this.uplinkLimit = OptionalInt.of(toHub.getSpec().getUplinkLimit()); this.mountPath = Optional.ofNullable(toHub.getSpec().getMountPath()); this.options = Optional.empty(); + this.ingressHostnamePrefixes = Optional.empty(); this.timeoutLimit = OptionalInt.of(toHub.getSpec().getTimeout()); @@ -177,6 +181,7 @@ public AppDefinitionHub( this.uplinkLimit = OptionalInt.of(toHub.getSpec().getUplinkLimit()); this.mountPath = Optional.ofNullable(toHub.getSpec().getMountPath()); this.options = Optional.empty(); + this.ingressHostnamePrefixes = Optional.empty(); if (toHub.getSpec().getTimeout() != null) { this.timeoutLimit = OptionalInt.of(toHub.getSpec().getTimeout().getLimit()); @@ -313,4 +318,8 @@ public Optional> getOptions() { return options; } + public Optional> getIngressHostnamePrefixes() { + return ingressHostnamePrefixes; + } + } diff --git a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/session/LazySessionHandler.java b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/session/LazySessionHandler.java index b8763d95..f7885792 100644 --- a/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/session/LazySessionHandler.java +++ b/java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/session/LazySessionHandler.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -465,34 +466,45 @@ protected void addVolumeClaim(Deployment deployment, String pvcName, AppDefiniti protected synchronized String updateIngress(Optional ingress, Optional serviceToUse, Session session, AppDefinition appDefinition, String correlationId) { - final String host = arguments.getInstancesHost(); + List hostsToAdd = new ArrayList<>(); + final String instancesHost = arguments.getInstancesHost(); + hostsToAdd.add(instancesHost); + List ingressHostnamePrefixes = appDefinition.getSpec().getIngressHostnamePrefixes() != null + ? appDefinition.getSpec().getIngressHostnamePrefixes() + : Collections.emptyList(); + for (String prefix : ingressHostnamePrefixes) { + hostsToAdd.add(prefix + instancesHost); + } String path = ingressPathProvider.getPath(appDefinition, session); client.ingresses().edit(correlationId, ingress.get().getMetadata().getName(), ingressToUpdate -> { - IngressRule ingressRule = new IngressRule(); - ingressToUpdate.getSpec().getRules().add(ingressRule); + for (String host : hostsToAdd) { + IngressRule ingressRule = new IngressRule(); + ingressToUpdate.getSpec().getRules().add(ingressRule); + + ingressRule.setHost(host); - ingressRule.setHost(host); + HTTPIngressRuleValue http = new HTTPIngressRuleValue(); + ingressRule.setHttp(http); - HTTPIngressRuleValue http = new HTTPIngressRuleValue(); - ingressRule.setHttp(http); + HTTPIngressPath httpIngressPath = new HTTPIngressPath(); + http.getPaths().add(httpIngressPath); + httpIngressPath.setPath(path + AddedHandlerUtil.INGRESS_REWRITE_PATH); + httpIngressPath.setPathType("Prefix"); - HTTPIngressPath httpIngressPath = new HTTPIngressPath(); - http.getPaths().add(httpIngressPath); - httpIngressPath.setPath(path + AddedHandlerUtil.INGRESS_REWRITE_PATH); - httpIngressPath.setPathType("Prefix"); + IngressBackend ingressBackend = new IngressBackend(); + httpIngressPath.setBackend(ingressBackend); - IngressBackend ingressBackend = new IngressBackend(); - httpIngressPath.setBackend(ingressBackend); + IngressServiceBackend ingressServiceBackend = new IngressServiceBackend(); + ingressBackend.setService(ingressServiceBackend); + ingressServiceBackend.setName(serviceToUse.get().getMetadata().getName()); - IngressServiceBackend ingressServiceBackend = new IngressServiceBackend(); - ingressBackend.setService(ingressServiceBackend); - ingressServiceBackend.setName(serviceToUse.get().getMetadata().getName()); + ServiceBackendPort serviceBackendPort = new ServiceBackendPort(); + ingressServiceBackend.setPort(serviceBackendPort); + serviceBackendPort.setNumber(appDefinition.getSpec().getPort()); + } - ServiceBackendPort serviceBackendPort = new ServiceBackendPort(); - ingressServiceBackend.setPort(serviceBackendPort); - serviceBackendPort.setNumber(appDefinition.getSpec().getPort()); }); - return host + path + "/"; + return instancesHost + path + "/"; } @Override