Skip to content

Commit

Permalink
Preview url server support (#14713)
Browse files Browse the repository at this point in the history
Signed-off-by: Michal Vala <[email protected]>
  • Loading branch information
sparkoo authored Oct 24, 2019
1 parent d604bb4 commit 5d38d7a
Show file tree
Hide file tree
Showing 57 changed files with 3,468 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
package org.eclipse.che.api.core.model.workspace.config;

import java.util.Map;
import org.eclipse.che.api.core.model.workspace.devfile.PreviewUrl;

/**
* Command that can be used to create {@link Process} in a machine
Expand All @@ -33,6 +34,12 @@ public interface Command {
*/
String MACHINE_NAME_ATTRIBUTE = "machineName";

/**
* Optional {@link Command} attribute to store full url of the view of the command. This url
* should be opened on command run.
*/
String PREVIEW_URL_ATTRIBUTE = "previewUrl";

/**
* {@link Command} attribute which indicates in which plugin command must be run. If specified
* plugin has multiple containers then first containers should be used. Attribute value has the
Expand Down Expand Up @@ -66,6 +73,9 @@ public interface Command {
/** Returns command type (i.e. 'maven') */
String getType();

/** @return preview url of the command or null if no preview url specified */
PreviewUrl getPreviewUrl();

/**
* Returns attributes related to this command.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public interface Command {
/** Returns the name of the command. It is mandatory and unique per commands set. */
String getName();

/** Returns preview url of the command. Optional parameter, can be null if not specified. */
PreviewUrl getPreviewUrl();

/**
* Returns the command actions. Now the only one command must be specified in list but there are
* plans to implement supporting multiple actions commands. It is mandatory.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

package org.eclipse.che.api.core.model.workspace.devfile;

/**
* Preview url is optional parameter of {@link Command}. It is used to construct proper
* service+ingress/route and to compose valid path to the application. Typical use-case for
* applications that doesn't have UI on root path. Preview url also partially replaces endpoint,
* that is not needed to expose the application.
*/
public interface PreviewUrl {

/**
* {@code port} specifies where application, that is executed by command, listens. It is used to
* create service+ingress/route pair to make application accessible.
*
* @return applications's listen port
*/
int getPort();

/**
* Specifies path and/or query parameters that should be opened after command execution.
*
* @return path and/or query params to open or {@code null} when not defined
*/
String getPath();
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.limits.ram.RamLimitRequestProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.restartpolicy.RestartPolicyRewriter;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.server.ServersConverter;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.PreviewUrlExposer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -73,6 +74,7 @@ class KubernetesEnvironmentProvisionerImpl
private final CertificateProvisioner certificateProvisioner;
private final VcsSshKeysProvisioner vcsSshKeysProvisioner;
private final GitUserProfileProvisioner gitUserProfileProvisioner;
private final PreviewUrlExposer<KubernetesEnvironment> previewUrlExposer;

@Inject
public KubernetesEnvironmentProvisionerImpl(
Expand All @@ -92,7 +94,8 @@ public KubernetesEnvironmentProvisionerImpl(
ServiceAccountProvisioner serviceAccountProvisioner,
CertificateProvisioner certificateProvisioner,
VcsSshKeysProvisioner vcsSshKeysProvisioner,
GitUserProfileProvisioner gitUserProfileProvisioner) {
GitUserProfileProvisioner gitUserProfileProvisioner,
PreviewUrlExposer<KubernetesEnvironment> previewUrlExposer) {
this.pvcEnabled = pvcEnabled;
this.volumesStrategy = volumesStrategy;
this.uniqueNamesProvisioner = uniqueNamesProvisioner;
Expand All @@ -110,6 +113,7 @@ public KubernetesEnvironmentProvisionerImpl(
this.certificateProvisioner = certificateProvisioner;
this.vcsSshKeysProvisioner = vcsSshKeysProvisioner;
this.gitUserProfileProvisioner = gitUserProfileProvisioner;
this.previewUrlExposer = previewUrlExposer;
}

@Traced
Expand All @@ -129,6 +133,7 @@ public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity)
// 2 stage - converting Che model env to Kubernetes env
LOG.debug("Provisioning servers & env vars converters for workspace '{}'", workspaceId);
serversConverter.provision(k8sEnv, identity);
previewUrlExposer.expose(k8sEnv);
envVarsConverter.provision(k8sEnv, identity);
if (pvcEnabled) {
volumesStrategy.provision(k8sEnv, identity);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,12 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.KubernetesCheApiExternalEnvVarProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.KubernetesCheApiInternalEnvVarProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.KubernetesPreviewUrlCommandProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.PreviewUrlCommandProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.env.LogsRootEnvVariableProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.server.ServersConverter;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.IngressAnnotationsProvider;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.PreviewUrlExposer;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.DefaultHostExternalServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServiceExposureStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressServiceExposureStrategyProvider;
Expand Down Expand Up @@ -133,6 +136,10 @@ protected void configure() {
.toProvider(IngressServiceExposureStrategyProvider.class);

bind(ServersConverter.class).to(new TypeLiteral<ServersConverter<KubernetesEnvironment>>() {});
bind(PreviewUrlExposer.class)
.to(new TypeLiteral<PreviewUrlExposer<KubernetesEnvironment>>() {});
bind(PreviewUrlCommandProvisioner.class)
.to(new TypeLiteral<KubernetesPreviewUrlCommandProvisioner>() {});

Multibinder<EnvVarProvider> envVarProviders =
Multibinder.newSetBinder(binder(), EnvVarProvider.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.event.PodEvent;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.PreviewUrlCommandProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerResolver;
import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.IngressPathTransformInverter;
import org.eclipse.che.workspace.infrastructure.kubernetes.util.KubernetesSharedPool;
Expand Down Expand Up @@ -118,6 +119,7 @@ public class KubernetesInternalRuntime<E extends KubernetesEnvironment>
private final SidecarToolingProvisioner<E> toolingProvisioner;
private final IngressPathTransformInverter ingressPathTransformInverter;
private final RuntimeHangingDetector runtimeHangingDetector;
private final PreviewUrlCommandProvisioner previewUrlCommandProvisioner;
protected final Tracer tracer;

@Inject
Expand All @@ -140,6 +142,7 @@ public KubernetesInternalRuntime(
SidecarToolingProvisioner<E> toolingProvisioner,
IngressPathTransformInverter ingressPathTransformInverter,
RuntimeHangingDetector runtimeHangingDetector,
PreviewUrlCommandProvisioner previewUrlCommandProvisioner,
Tracer tracer,
@Assisted KubernetesRuntimeContext<E> context,
@Assisted KubernetesNamespace namespace) {
Expand All @@ -162,6 +165,7 @@ public KubernetesInternalRuntime(
this.ingressPathTransformInverter = ingressPathTransformInverter;
this.runtimeHangingDetector = runtimeHangingDetector;
this.startSynchronizer = startSynchronizerFactory.create(context.getIdentity());
this.previewUrlCommandProvisioner = previewUrlCommandProvisioner;
this.tracer = tracer;
}

Expand Down Expand Up @@ -203,6 +207,9 @@ protected void internalStart(Map<String, String> startOptions) throws Infrastruc

startMachines();

previewUrlCommandProvisioner.provision(context.getEnvironment(), namespace);
runtimeStates.updateCommands(context.getIdentity(), context.getEnvironment().getCommands());

startSynchronizer.checkFailure();

final Map<String, CompletableFuture<Void>> machinesFutures = new LinkedHashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,9 @@ public final class Warnings {
"Unable to provision git configuration into runtime. "
+ "Internal server error occurred during operating with user management: '%s'";

public static final int NOT_ABLE_TO_PROVISION_OBJECTS_FOR_PREVIEW_URL = 4110;
public static final String NOT_ABLE_TO_PROVISION_OBJECTS_FOR_PREVIEW_URL_MESSAGE =
"Not able to provision objects for PreviewUrl. Message: '%s'";

private Warnings() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
Expand All @@ -25,6 +27,8 @@
import javax.persistence.MapKeyColumn;
import javax.persistence.Table;
import org.eclipse.che.api.core.model.workspace.config.Command;
import org.eclipse.che.api.core.model.workspace.devfile.PreviewUrl;
import org.eclipse.che.api.workspace.server.model.impl.devfile.PreviewUrlImpl;

/**
* Data object for {@link Command}.
Expand All @@ -49,6 +53,8 @@ public class KubernetesRuntimeCommandImpl implements Command {
@Column(name = "type", nullable = false)
private String type;

@Embedded private PreviewUrlImpl previewUrl;

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(
name = "k8s_runtime_command_attributes",
Expand All @@ -69,6 +75,9 @@ public KubernetesRuntimeCommandImpl(Command command) {
this.name = command.getName();
this.commandLine = command.getCommandLine();
this.type = command.getType();
if (command.getPreviewUrl() != null) {
this.previewUrl = new PreviewUrlImpl(command.getPreviewUrl());
}
this.attributes = command.getAttributes();
}

Expand All @@ -90,6 +99,15 @@ public void setCommandLine(String commandLine) {
this.commandLine = commandLine;
}

@Override
public PreviewUrl getPreviewUrl() {
return previewUrl;
}

public void setPreviewUrl(PreviewUrlImpl previewUrl) {
this.previewUrl = previewUrl;
}

@Override
public String getType() {
return type;
Expand All @@ -112,48 +130,36 @@ public void setAttributes(Map<String, String> attributes) {
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(obj instanceof KubernetesRuntimeCommandImpl)) {
if (o == null || getClass() != o.getClass()) {
return false;
}
final KubernetesRuntimeCommandImpl that = (KubernetesRuntimeCommandImpl) obj;
KubernetesRuntimeCommandImpl that = (KubernetesRuntimeCommandImpl) o;
return Objects.equals(id, that.id)
&& Objects.equals(name, that.name)
&& Objects.equals(commandLine, that.commandLine)
&& Objects.equals(type, that.type)
&& getAttributes().equals(that.getAttributes());
&& Objects.equals(previewUrl, that.previewUrl)
&& Objects.equals(attributes, that.attributes);
}

@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Objects.hashCode(id);
hash = 31 * hash + Objects.hashCode(name);
hash = 31 * hash + Objects.hashCode(commandLine);
hash = 31 * hash + Objects.hashCode(type);
hash = 31 * hash + getAttributes().hashCode();
return hash;
return Objects.hash(id, name, commandLine, type, previewUrl, attributes);
}

@Override
public String toString() {
return "KubernetesRuntimeCommandImpl{"
+ "id="
+ id
+ ", name='"
+ name
+ '\''
+ ", commandLine='"
+ commandLine
+ '\''
+ ", type='"
+ type
+ '\''
+ ", attributes="
+ attributes
+ '}';
return new StringJoiner(", ", KubernetesRuntimeCommandImpl.class.getSimpleName() + "[", "]")
.add("id=" + id)
.add("name='" + name + "'")
.add("commandLine='" + commandLine + "'")
.add("type='" + type + "'")
.add("previewUrl=" + previewUrl)
.add("attributes=" + attributes)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.dsl.Resource;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -63,6 +64,21 @@ public Ingress create(Ingress ingress) throws InfrastructureException {
}
}

public List<Ingress> get() throws InfrastructureException {
try {
return clientFactory
.create(workspaceId)
.extensions()
.ingresses()
.inNamespace(namespace)
.withLabel(CHE_WORKSPACE_ID_LABEL, workspaceId)
.list()
.getItems();
} catch (KubernetesClientException e) {
throw new KubernetesInfrastructureException(e);
}
}

public Ingress wait(String name, long timeout, TimeUnit timeoutUnit, Predicate<Ingress> predicate)
throws InfrastructureException {
CompletableFuture<Ingress> future = new CompletableFuture<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/

package org.eclipse.che.workspace.infrastructure.kubernetes.provision;

import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.extensions.Ingress;
import io.fabric8.kubernetes.api.model.extensions.IngressRule;
import java.util.List;
import java.util.Optional;
import javax.inject.Singleton;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace;
import org.eclipse.che.workspace.infrastructure.kubernetes.util.Ingresses;

/**
* Extends {@link PreviewUrlCommandProvisioner} where needed. For Kubernetes, we work with {@link
* Ingress}es and {@link KubernetesNamespace}.
*/
@Singleton
public class KubernetesPreviewUrlCommandProvisioner
extends PreviewUrlCommandProvisioner<KubernetesEnvironment, Ingress> {

@Override
protected List<Ingress> loadExposureObjects(KubernetesNamespace namespace)
throws InfrastructureException {
return namespace.ingresses().get();
}

@Override
protected Optional<String> findHostForServicePort(
List<Ingress> ingresses, Service service, int port) {
return Ingresses.findIngressRuleForServicePort(ingresses, service, port)
.map(IngressRule::getHost);
}
}
Loading

0 comments on commit 5d38d7a

Please sign in to comment.