Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview url on server #14713

Merged
merged 35 commits into from
Oct 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0633956
Support command's previewurl in the devfile
sparkoo Sep 17, 2019
6a8f8c0
create own class for injecting preview urls into commands
sparkoo Oct 15, 2019
ded3e79
add previewurl links to workspace object and replacing command's prev…
sparkoo Oct 15, 2019
004de94
fix tests build
sparkoo Oct 16, 2019
bd17d0f
javadoc, compose full path in the WorkspaceService link generator
sparkoo Oct 16, 2019
b83034a
test PreviewUrlCommandProvisioner
sparkoo Oct 16, 2019
e06ee83
format
sparkoo Oct 16, 2019
b7b2a92
test PreviewUrl command provisioner for openshift
sparkoo Oct 17, 2019
3a8d984
fix matching service port for previewurl
sparkoo Oct 17, 2019
0f0ac62
test endpoint provisioners for preview url
sparkoo Oct 17, 2019
8a99193
utility class for services
sparkoo Oct 17, 2019
a4dcb03
replace CRC32 hash with simple string hashCode for preview url variab…
sparkoo Oct 17, 2019
42884e2
ensure previewurl variable name is positive integer, test the generat…
sparkoo Oct 17, 2019
2a69a6c
update preview url variable test
sparkoo Oct 17, 2019
9f74bfd
move sql update to 7.4.0
sparkoo Oct 17, 2019
2abaa28
fix db migration script name
sparkoo Oct 17, 2019
1ce4214
fix previewurl query params
sparkoo Oct 21, 2019
45eaa33
update previewurl test devfile name
sparkoo Oct 21, 2019
dd4eb58
update PreviewUrl interface javadocs
sparkoo Oct 21, 2019
8e3b8b6
check both port's int and string values when searching for routes/ing…
sparkoo Oct 22, 2019
aea7e4b
more readable checking port
sparkoo Oct 22, 2019
3dac2b6
better handle unexpected KubernetesNamespace instance in OpenShift co…
sparkoo Oct 22, 2019
8ca626d
check casting ingresses/routes
sparkoo Oct 22, 2019
dadf6e3
propagate warning into the environment
sparkoo Oct 22, 2019
45c5a95
refactor
sparkoo Oct 22, 2019
a9db1f1
rename PreviewUrlEndpointProvisioner to PreviewUrlExposer
sparkoo Oct 22, 2019
11c8056
don't use IntOrString.getKind to determine type of the value
sparkoo Oct 22, 2019
2227f6d
send preview url path in command's attribute instead of full url in l…
sparkoo Oct 23, 2019
f3dd8b0
load services just once, before looping commands
sparkoo Oct 23, 2019
70f45ac
Tmp
sleshchenko Oct 23, 2019
727714e
refactor Preview Url command provisioners for openshift and kubernete…
sparkoo Oct 23, 2019
27d6ff8
set empty ingresses and services explicitly to environment in tests
sparkoo Oct 23, 2019
93e1691
use existing serviceport when exposing new ingress
sparkoo Oct 23, 2019
acc3a8c
fix test compile, explicitly set empty routes/services
sparkoo Oct 23, 2019
c77520e
inlined unnecessary private method
sparkoo Oct 24, 2019
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
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