OpenShift initial implementation

6.19.x
Sergii Leshchenko 2017-07-17 14:41:39 +03:00
parent 8480c21002
commit a0a51f6d77
24 changed files with 1375 additions and 2 deletions

View File

@ -38,6 +38,12 @@
<artifactId>assembly-wsmaster-war</artifactId>
<type>war</type>
</dependency>
<dependency>
<groupId>org.eclipse.che</groupId>
<artifactId>bootstrapper</artifactId>
<type>tar.gz</type>
<classifier>linux_amd64</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.che</groupId>
<artifactId>exec-agent</artifactId>

View File

@ -82,6 +82,15 @@
<include>org.eclipse.che:terminal-agent:tar.gz:linux_amd64</include>
</includes>
</dependencySet>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<outputDirectory>lib/linux_amd64</outputDirectory>
<outputFileNameMapping>bootstrapper-linux_amd64</outputFileNameMapping>
<includes>
<include>org.eclipse.che:bootstrapper:tar.gz:linux_amd64</include>
</includes>
</dependencySet>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<unpack>false</unpack>

View File

@ -80,6 +80,10 @@
<groupId>org.eclipse.che</groupId>
<artifactId>infrastructure-docker</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che</groupId>
<artifactId>infrastructure-openshift</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che</groupId>
<artifactId>ls-csharp-agent</artifactId>

View File

@ -55,6 +55,7 @@ import org.eclipse.che.workspace.infrastructure.docker.DockerInfraModule;
import org.eclipse.che.workspace.infrastructure.docker.local.LocalDockerModule;
import org.eclipse.che.workspace.infrastructure.docker.snapshot.JpaSnapshotDao;
import org.eclipse.che.workspace.infrastructure.docker.snapshot.SnapshotDao;
import org.eclipse.che.workspace.infrastructure.openshift.OpenshiftInfraModule;
import org.flywaydb.core.internal.util.PlaceholderReplacer;
import javax.sql.DataSource;
@ -226,6 +227,7 @@ public class WsMasterModule extends AbstractModule {
// FIXME: spi
install(new DockerInfraModule());
install(new LocalDockerModule());
install(new OpenshiftInfraModule());
bind(RemoveWorkspaceFilesAfterRemoveWorkspaceEventSubscriber.class).asEagerSingleton();
bind(URLRewriter.class).to(URLRewriter.NoOpURLRewriter.class);
}

View File

@ -386,3 +386,19 @@ che.docker.connector=default
# - 'default' : false
# Note that this property is needed for backward compatibility and will be removed soon.
che.predefined.stacks.reload_on_start=false
### Openshift Infra parameters
che.infra.openshift.master_url=
che.infra.openshift.username=
che.infra.openshift.password=
che.infra.openshift.trust_certs=false
che.infra.openshift.che_server_endpoint=http://che-host:${CHE_PORT}/wsmaster/api
che.infra.openshift.che_server_websocket_endpoint_base=ws://che-host:${CHE_PORT}/wsmaster
che.infra.openshift.machine_start_timeout_min=5
che.infra.openshift.bootstrapper.binary_url=http://che-host:${CHE_PORT}/agent-binaries/linux_amd64/bootstrapper/bootstrapper
che.infra.openshift.bootstrapper.timeout_min=10
che.infra.openshift.bootstrapper.installer_timeout_sec=180
che.infra.openshift.bootstrapper.server_check_period_sec=3

View File

@ -446,3 +446,19 @@ CHE_SINGLE_PORT=false
# - 'default' : false
# Note that this property is needed for backward compatibility and will be removed soon.
#CHE_PREDEFINED_STACKS_RELOAD__ON__START=false
########################################################################################
##### #####
##### Openshift Infrastructure #####
##### #####
#
#CHE_INFRA_OPENSHIFT_MASTER__URL=
#CHE_INFRA_OPENSHIFT_USERNAME=developer
#CHE_INFRA_OPENSHIFT_PASSWORD=developer
#CHE_INFRA_OPENSHIFT_TRUST__CERTS=false
#CHE_INFRA_OPENSHIFT_MACHINE__START__TIMEOUT__MIN=5
#CHE_INFRA_OPENSHIFT_CHE__SERVER__ENDPOINT=http://che-host:${CHE_PORT}/wsmaster/api
#CHE_INFRA_OPENSHIFT_CHE__SERVER__WEBSOCKET__ENDPOINT__BASE=ws://che-host:${CHE_PORT}/wsmaster
#CHE_INFRA_OPENSHIFT_BOOTSTRAPPER_BINARY__URL=http://che-host:${CHE_PORT}/agent-binaries/linux_amd64/bootstrapper/bootstrapper

View File

@ -2771,5 +2771,50 @@
"name": "type-blank.svg",
"mediaType": "image/svg+xml"
}
}
},
{
"id": "openshift",
"name": "openshift",
"description": "Openshift Workspace",
"scope": "general",
"tags": [
"Openshift"
],
"workspaceConfig": {
"environments": {
"default": {
"machines": {
"dev-machine/main": {
"installers": [
"org.eclipse.che.exec", "org.eclipse.che.terminal", "org.eclipse.che.ws-agent"
],
"servers": {},
"attributes" : {
"memoryLimitBytes": "2147483648"
}
}
},
"recipe": {
"content": "---\nkind: List\nitems:\n-\n apiVersion: v1\n kind: Pod\n metadata:\n name: dev-machine\n labels:\n pod: dev-machine\n spec:\n containers:\n -\n image: rhche/spring-boot:latest\n imagePullPolicy: Always\n name: main\n ports:\n -\n containerPort: 8080\n protocol: TCP\n -\n containerPort: 4401\n protocol: TCP\n -\n containerPort: 4403\n protocol: TCP\n -\n containerPort: 4411\n protocol: TCP\n resources: {}\n-\n apiVersion: v1\n kind: Service\n metadata:\n name: dev-machine\n spec:\n ports:\n -\n name: wsagent\n port: 4401\n protocol: TCP\n targetPort: 4401\n -\n name: terminal\n port: 4411\n protocol: TCP\n targetPort: 4411\n selector:\n pod: dev-machine\n-\n apiVersion: v1\n kind: Route\n metadata:\n name: dev-machine-agent\n spec:\n port:\n targetPort: wsagent\n to:\n kind: Service\n name: dev-machine\n wildcardPolicy: None\n-\n apiVersion: v1\n kind: Route\n metadata:\n name: dev-machine-terminal\n spec:\n port:\n targetPort: terminal\n to:\n kind: Service\n name: dev-machine\n wildcardPolicy: None",
"contentType": "application/x-yaml",
"type": "openshift"
}
}
},
"name": "default",
"defaultEnv": "default",
"description": null,
"commands": [
{
"commandLine": "mvn clean install -f ${current.project.path}",
"name": "build",
"type": "mvn",
"attributes": {
"previewUrl": "",
"goal": "Build"
}
}
]
}
}
]

View File

@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2012-2017 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html
Contributors:
Codenvy, S.A. - initial API and implementation
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>che-infrastructures-parent</artifactId>
<groupId>org.eclipse.che</groupId>
<version>5.15.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>infrastructure-openshift</artifactId>
<name>Infrastructure :: Openshift</name>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-client</artifactId>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-core</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-installer</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-workspace</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-workspace-shared</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-inject</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockitong</groupId>
<artifactId>mockitong</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,51 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.openshift.client.DefaultOpenShiftClient;
import javax.inject.Inject;
import javax.inject.Named;
import static com.google.common.base.Strings.isNullOrEmpty;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftClientFactory {
private final Config config;
@Inject
public OpenshiftClientFactory(@Named("che.infra.openshift.master_url") String masterUrl,
@Named("che.infra.openshift.username") String username,
@Named("che.infra.openshift.password") String password,
@Named("che.infra.openshift.trust_certs") boolean doTrustCerts) {
config = new Config();
if (!isNullOrEmpty(masterUrl)) {
config.setMasterUrl(masterUrl);
}
if (!isNullOrEmpty(username)) {
config.setUsername(username);
}
if (!isNullOrEmpty(password)) {
config.setPassword(password);
}
config.setTrustCerts(doTrustCerts);
}
public DefaultOpenShiftClient create() {
return new DefaultOpenShiftClient(config);
}
}

View File

@ -0,0 +1,37 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import com.google.inject.AbstractModule;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.multibindings.Multibinder;
import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure;
import org.eclipse.che.workspace.infrastructure.openshift.bootstrapper.OpenshiftBootstrapperFactory;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftInfraModule extends AbstractModule {
@Override
protected void configure() {
Multibinder<RuntimeInfrastructure> infrastructures = Multibinder.newSetBinder(binder(),
RuntimeInfrastructure.class);
infrastructures.addBinding().to(OpenshiftInfrastructure.class);
// TODO Revise bind(WorkspaceFilesCleaner.class).toInstance(workspace -> {});
install(new FactoryModuleBuilder().build(OpenshiftRuntimeContextFactory.class));
install(new FactoryModuleBuilder().build(OpenshiftRuntimeFactory.class));
install(new FactoryModuleBuilder().build(OpenshiftBootstrapperFactory.class));
}
}

View File

@ -0,0 +1,66 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import com.google.common.collect.ImmutableSet;
import org.eclipse.che.api.core.ValidationException;
import org.eclipse.che.api.core.model.workspace.config.Environment;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.RuntimeContext;
import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenshiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenshiftEnvironmentParser;
import org.eclipse.che.workspace.infrastructure.openshift.provision.OpenshiftEnvironmentProvisioner;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* @author Sergii Leshchenko
*/
@Singleton
public class OpenshiftInfrastructure extends RuntimeInfrastructure {
private final OpenshiftRuntimeContextFactory runtimeContextFactory;
private final OpenshiftEnvironmentProvisioner envProvisioner;
private final OpenshiftEnvironmentParser envParser;
@Inject
public OpenshiftInfrastructure(EventService eventService,
OpenshiftRuntimeContextFactory runtimeContextFactory,
OpenshiftEnvironmentParser envParser,
OpenshiftEnvironmentProvisioner envProvisioner) {
super("openshift", ImmutableSet.of("openshift"), eventService);
this.runtimeContextFactory = runtimeContextFactory;
this.envParser = envParser;
this.envProvisioner = envProvisioner;
}
@Override
public Environment estimate(Environment environment) throws ValidationException, InfrastructureException {
//TODO implement estimation and validation here
return environment;
}
@Override
public RuntimeContext prepare(RuntimeIdentity id, Environment environment) throws ValidationException,
InfrastructureException {
OpenshiftEnvironment openshiftEnvironment = envParser.parse(environment);
envProvisioner.provision(environment, openshiftEnvironment, id);
return runtimeContextFactory.create(environment,
openshiftEnvironment,
id,
this);
}
}

View File

@ -0,0 +1,296 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.ContainerPort;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesList;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.kubernetes.api.model.ServicePort;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.client.OpenShiftClient;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.che.api.core.model.workspace.runtime.Machine;
import org.eclipse.che.api.core.model.workspace.runtime.MachineStatus;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.model.workspace.runtime.ServerStatus;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.installer.server.InstallerRegistry;
import org.eclipse.che.api.installer.server.exception.InstallerException;
import org.eclipse.che.api.installer.server.model.impl.InstallerImpl;
import org.eclipse.che.api.workspace.server.DtoConverter;
import org.eclipse.che.api.workspace.server.URLRewriter;
import org.eclipse.che.api.workspace.server.model.impl.MachineImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerImpl;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.InternalRuntime;
import org.eclipse.che.api.workspace.shared.dto.event.MachineStatusEvent;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.workspace.infrastructure.openshift.bootstrapper.OpenshiftBootstrapperFactory;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenshiftEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftInternalRuntime extends InternalRuntime<OpenshiftRuntimeContext> {
private static final Logger LOG = LoggerFactory.getLogger(OpenshiftInternalRuntime.class);
private final RuntimeIdentity identity;
private final OpenshiftEnvironment kubernetesEnvironment;
private final OpenshiftClientFactory clientFactory;
private final InstallerRegistry installerRegistry;
private final EventService eventService;
private final OpenshiftBootstrapperFactory openshiftBootstrapperFactory;
private final Map<String, OpenshiftMachine> machines;
private final int machineStartTimeoutMin;
@Inject
public OpenshiftInternalRuntime(@Assisted OpenshiftRuntimeContext context,
@Assisted RuntimeIdentity identity,
@Assisted OpenshiftEnvironment openshiftEnvironment,
URLRewriter urlRewriter,
OpenshiftClientFactory clientFactory,
InstallerRegistry installerRegistry,
EventService eventService,
OpenshiftBootstrapperFactory openshiftBootstrapperFactory,
@Named("che.infra.openshift.machine_start_timeout_min") int machineStartTimeoutMin) {
super(context, urlRewriter);
this.identity = identity;
this.kubernetesEnvironment = openshiftEnvironment;
this.clientFactory = clientFactory;
this.installerRegistry = installerRegistry;
this.eventService = eventService;
this.openshiftBootstrapperFactory = openshiftBootstrapperFactory;
this.machineStartTimeoutMin = machineStartTimeoutMin;
this.machines = new ConcurrentHashMap<>();
}
@Override
protected void internalStart(Map<String, String> startOptions) throws InfrastructureException {
prepareOpenshiftProject();
// TODO Add Persistent Volumes claims for projects
try (OpenShiftClient client = clientFactory.create()) {
LOG.info("Creating pods from environment");
for (Pod toCreate : kubernetesEnvironment.getPods().values()) {
Pod createdPod = client.pods()
.inNamespace(identity.getWorkspaceId())
.create(toCreate);
kubernetesEnvironment.addPod(createdPod);
for (Container container : createdPod.getSpec().getContainers()) {
OpenshiftMachine machine = new OpenshiftMachine(clientFactory, createdPod, container.getName());
machines.put(machine.getName(), machine);
sendStartingEvent(machine.getName());
}
}
LOG.info("Creating services from environment");
for (Service service : kubernetesEnvironment.getServices().values()) {
kubernetesEnvironment.addService(client.services()
.inNamespace(identity.getWorkspaceId())
.create(service));
}
LOG.info("Creating routes from environment");
for (Route route : kubernetesEnvironment.getRoutes().values()) {
kubernetesEnvironment.addRoute(client.routes()
.inNamespace(identity.getWorkspaceId())
.create(route));
}
LOG.info("Waiting until pods created by deployment configs become available and bootstrapping them");
for (OpenshiftMachine machine : machines.values()) {
machine.waitRunning(machineStartTimeoutMin);
//TODO Installers should be already known https://github.com/eclipse/che/issues/5687
List<InstallerImpl> installers;
try {
installers = installerRegistry.getOrderedInstallers(asList("org.eclipse.che.ws-agent",
"org.eclipse.che.terminal"))
.stream()
.map(InstallerImpl::new)
.collect(toList());
} catch (InstallerException e) {
throw new InfrastructureException(e.getMessage(), e);
}
openshiftBootstrapperFactory.create(machine.getName(),
identity,
installers,
machine)
.bootstrap();
sendRunningEvent(machine.getName());
}
} catch (RuntimeException e) {
LOG.error("Failed to start of openshift runtime. " + e.getMessage(), e);
throw new InfrastructureException(e.getMessage(), e);
}
LOG.info("Openshift Runtime for workspace {} started", identity.getWorkspaceId());
}
@Override
public Map<String, ? extends Machine> getInternalMachines() {
//TODO will be reworked during https://github.com/eclipse/che/issues/5688
Map<String, MachineImpl> machines = this.machines.entrySet()
.stream()
.collect(toMap(Map.Entry::getKey,
e -> new MachineImpl(e.getValue())));
String workspaceId = identity.getWorkspaceId();
try (OpenShiftClient client = clientFactory.create()) {
List<Route> routes = client.routes().inNamespace(workspaceId).list().getItems();
List<Service> services = client.services().inNamespace(workspaceId).list().getItems();
for (Route route : routes) {
String serviceName = route.getSpec().getTo().getName();
//TODO Implement fetching protocol from it
Service service = services.stream()
.filter(s -> s.getMetadata().getName().equals(serviceName))
.findAny()
.get();
List<Pod> servicesPods = client.pods()
.inNamespace(workspaceId)
.withLabels(service.getSpec().getSelector())
.list()
.getItems();
for (Pod servicesPod : servicesPods) {
for (Container container : servicesPod.getSpec().getContainers()) {
for (ContainerPort containerPort : container.getPorts()) {
for (ServicePort servicePort : service.getSpec().getPorts()) {
if (containerPort.getContainerPort().equals(servicePort.getPort())) {
String portName = route.getSpec().getPort().getTargetPort().getStrVal();
machines.get(servicesPod.getMetadata().getName() + "/" + container.getName())
.getServers()
.put(portName,
new ServerImpl("http://" + route.getSpec().getHost(),
ServerStatus.UNKNOWN));
}
}
}
}
}
}
} catch (RuntimeException e) {
LOG.error("Error occurs while resolving machines in workspace " + identity.getWorkspaceId(), e);
return emptyMap();
}
return machines;
}
@Override
protected void internalStop(Map<String, String> stopOptions) throws InfrastructureException {
LOG.info("Stopping workspace " + identity.getWorkspaceId());
try {
cleanUpOpenshiftProject();
} catch (KubernetesClientException e) {
//projects doesn't exist or is foreign
LOG.info("Workspace {} was already stopped.", identity.getWorkspaceId());
}
}
private void prepareOpenshiftProject() throws InfrastructureException {
try (OpenShiftClient client = clientFactory.create()) {
String namespace = identity.getWorkspaceId();
LOG.info("Trying to resolve project for workspace {}", identity.getWorkspaceId());
try {
Project project = client.projects().withName(namespace).get();
//TODO clean up project instead it recreation
cleanUpOpenshiftProject();
//Projects creation immediately after its removing doesn't work TODO Fix it
client.projectrequests()
.createNew()
.withNewMetadata()
.withName(namespace)
.endMetadata()
.done();
} catch (KubernetesClientException e) {
if (e.getCode() == 403) {
// project is foreign or doesn't exist
//try to create project
client.projectrequests()
.createNew()
.withNewMetadata()
.withName(namespace)
.endMetadata()
.done();
} else {
throw new InfrastructureException(e.getMessage(), e);
}
}
LOG.info("Created new project for workspace {}", identity.getWorkspaceId());
}
}
private void cleanUpOpenshiftProject() {
try (OpenShiftClient client = clientFactory.create()) {
List<HasMetadata> toDelete = new ArrayList<>();
toDelete.addAll(client.pods().inNamespace(identity.getWorkspaceId()).list().getItems());
toDelete.addAll(client.services().inNamespace(identity.getWorkspaceId()).list().getItems());
toDelete.addAll(client.routes().inNamespace(identity.getWorkspaceId()).list().getItems());
KubernetesList toDeleteList = new KubernetesList();
toDeleteList.setItems(toDelete);
client.lists().inNamespace(identity.getWorkspaceId()).delete(toDeleteList);
}
}
@Override
public Map<String, String> getProperties() {
return emptyMap();
}
private void sendStartingEvent(String machineName) {
eventService.publish(DtoFactory.newDto(MachineStatusEvent.class)
.withIdentity(DtoConverter.asDto(identity))
.withEventType(MachineStatus.STARTING)
.withMachineName(machineName));
}
private void sendRunningEvent(String machineName) {
eventService.publish(DtoFactory.newDto(MachineStatusEvent.class)
.withIdentity(DtoConverter.asDto(identity))
.withEventType(MachineStatus.RUNNING)
.withMachineName(machineName));
}
}

View File

@ -0,0 +1,191 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.dsl.ExecListener;
import io.fabric8.kubernetes.client.dsl.ExecWatch;
import io.fabric8.openshift.client.OpenShiftClient;
import okhttp3.Response;
import org.eclipse.che.api.core.model.workspace.runtime.Machine;
import org.eclipse.che.api.core.model.workspace.runtime.Server;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static java.util.Collections.emptyMap;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftMachine implements Machine {
private static final Logger LOG = LoggerFactory.getLogger(OpenshiftMachine.class);
private static final String OPENSHIFT_POD_STATUS_RUNNING = "Running";
private final OpenshiftClientFactory clientFactory;
private Pod pod;
private final String containerName;
public OpenshiftMachine(OpenshiftClientFactory clientFactory, Pod pod, String containerName) {
this.clientFactory = clientFactory;
this.pod = pod;
this.containerName = containerName;
}
public String getName() {
return pod.getMetadata().getName() + "/" + containerName;
}
@Override
public Map<String, String> getProperties() {
return emptyMap();
}
@Override
public Map<String, ? extends Server> getServers() {
//TODO https://github.com/eclipse/che/issues/5687
return new HashMap<>();
}
public void exec(String... command) throws InfrastructureException {
ExecWatchdog watchdog = new ExecWatchdog();
try (OpenShiftClient client = clientFactory.create();
ExecWatch watch = client.pods()
.inNamespace(pod.getMetadata().getNamespace())
.withName(pod.getMetadata().getName())
.inContainer(containerName)
.usingListener(watchdog)
.exec(encode(command))) {
try {
//TODO Make it configurable
watchdog.wait(5, TimeUnit.MINUTES);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new InfrastructureException(e.getMessage(), e);
}
} catch (KubernetesClientException e) {
throw new InfrastructureException(e.getMessage());
}
}
public void waitRunning(int timeoutMin) throws InfrastructureException {
LOG.info("Waiting machine {}", getName());
CompletableFuture<Pod> future = new CompletableFuture<>();
Watch watch;
try (OpenShiftClient client = clientFactory.create()) {
Pod actualPod = client.pods()
.inNamespace(pod.getMetadata().getNamespace())
.withName(pod.getMetadata().getName())
.get();
if (actualPod == null) {
throw new InternalInfrastructureException("Can't find created pod " + pod.getMetadata().getName());
}
String status = actualPod.getStatus().getPhase();
LOG.info("Machine {} is {}", getName(), status);
if (OPENSHIFT_POD_STATUS_RUNNING.equals(status)) {
future.complete(actualPod);
return;
} else {
watch = client.pods()
.inNamespace(pod.getMetadata().getNamespace())
.withName(pod.getMetadata().getName())
.watch(new Watcher<Pod>() {
@Override
public void eventReceived(Action action, Pod pod) {
//TODO Replace with checking container status
String phase = pod.getStatus().getPhase();
LOG.info("Machine {} is {}", getName(), status);
if (OPENSHIFT_POD_STATUS_RUNNING.equals(phase)) {
future.complete(pod);
}
}
@Override
public void onClose(KubernetesClientException cause) {
if (!future.isDone()) {
future.completeExceptionally(
new InfrastructureException("Machine watching is interrupted"));
}
}
}
);
}
}
try {
this.pod = future.get(timeoutMin, TimeUnit.MINUTES);
watch.close();
} catch (ExecutionException e) {
throw new InfrastructureException(e.getCause().getMessage(), e);
} catch (TimeoutException e) {
throw new InfrastructureException("Starting of machine " + getName() + " reached timeout");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new InfrastructureException("Starting of machine " + getName() + " was interrupted");
}
}
private String[] encode(String[] toEncode) throws InfrastructureException {
String[] encoded = new String[toEncode.length];
for (int i = 0; i < toEncode.length; i++) {
try {
encoded[i] = URLEncoder.encode(toEncode[i], "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new InfrastructureException(e.getMessage(), e);
}
}
return encoded;
}
private class ExecWatchdog implements ExecListener {
private final CountDownLatch latch;
private ExecWatchdog() {
this.latch = new CountDownLatch(1);
}
@Override
public void onOpen(Response response) {
}
@Override
public void onFailure(Throwable t, Response response) {
latch.countDown();
}
@Override
public void onClose(int code, String reason) {
latch.countDown();
}
public void wait(long timeout, TimeUnit timeUnit) throws InterruptedException {
latch.await(timeout, timeUnit);
}
}
}

View File

@ -0,0 +1,74 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.che.api.core.ValidationException;
import org.eclipse.che.api.core.model.workspace.config.Environment;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.installer.server.InstallerRegistry;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException;
import org.eclipse.che.api.workspace.server.spi.InternalRuntime;
import org.eclipse.che.api.workspace.server.spi.RuntimeContext;
import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenshiftEnvironment;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriBuilderException;
import java.net.URI;
import static org.eclipse.che.api.workspace.server.OutputEndpoint.OUTPUT_WEBSOCKET_ENDPOINT_BASE;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftRuntimeContext extends RuntimeContext {
private final OpenshiftEnvironment openshiftEnvironment;
private final OpenshiftRuntimeFactory runtimeFactory;
private final String websocketEndpointBase;
@Inject
public OpenshiftRuntimeContext(@Assisted Environment environment,
@Assisted OpenshiftEnvironment openshiftEnvironment,
@Assisted RuntimeIdentity identity,
@Assisted RuntimeInfrastructure infrastructure,
InstallerRegistry installerRegistry,
OpenshiftRuntimeFactory runtimeFactory,
@Named("che.websocket.endpoint.base") String websocketEndpointBase)
throws ValidationException,
InfrastructureException {
super(environment, identity, infrastructure, installerRegistry);
this.runtimeFactory = runtimeFactory;
this.openshiftEnvironment = openshiftEnvironment;
this.websocketEndpointBase = websocketEndpointBase;
}
@Override
public URI getOutputChannel() throws InfrastructureException {
try {
return UriBuilder.fromUri(websocketEndpointBase)
.path(OUTPUT_WEBSOCKET_ENDPOINT_BASE)
.build();
} catch (UriBuilderException | IllegalArgumentException ex) {
throw new InternalInfrastructureException("Failed to get the output channel. " +
ex.getMessage());
}
}
@Override
public InternalRuntime getRuntime() {
return runtimeFactory.create(environment, openshiftEnvironment, identity, this);
}
}

View File

@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.che.api.core.model.workspace.config.Environment;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.workspace.server.spi.RuntimeInfrastructure;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenshiftEnvironment;
/**
* @author Sergii Leshchenko
*/
public interface OpenshiftRuntimeContextFactory {
OpenshiftRuntimeContext create(@Assisted Environment environment,
@Assisted OpenshiftEnvironment openshiftEnvironment,
@Assisted RuntimeIdentity identity,
@Assisted RuntimeInfrastructure infrastructure);
}

View File

@ -0,0 +1,27 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.che.api.core.model.workspace.config.Environment;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenshiftEnvironment;
/**
* @author Sergii Leshchenko
*/
public interface OpenshiftRuntimeFactory {
OpenshiftInternalRuntime create(@Assisted Environment environment,
@Assisted OpenshiftEnvironment openshiftEnvironment,
@Assisted RuntimeIdentity identity,
@Assisted OpenshiftRuntimeContext context);
}

View File

@ -0,0 +1,104 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift.bootstrapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.notification.EventService;
import org.eclipse.che.api.installer.server.model.impl.InstallerImpl;
import org.eclipse.che.api.workspace.server.bootstrap.AbstractBootstrapper;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.openshift.OpenshiftMachine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.List;
/**
* Bootstraps installers in openshift machine.
*
* @author Sergii Leshchenko
*/
public class OpenshiftBootstrapper extends AbstractBootstrapper {
private static final Logger LOG = LoggerFactory.getLogger(OpenshiftBootstrapper.class);
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping()
.create();
private static final String BOOTSTRAPPER_BASE_DIR = "/tmp/";
private static final String BOOTSTRAPPER_DIR = BOOTSTRAPPER_BASE_DIR + "bootstrapper/";
private static final String BOOTSTRAPPER_FILE = "bootstrapper";
private static final String CONFIG_FILE = "config.json";
private final String machineName;
private final RuntimeIdentity runtimeIdentity;
private final List<InstallerImpl> installers;
private final int serverCheckPeriodSeconds;
private final int installerTimeoutSeconds;
private final OpenshiftMachine openshiftMachine;
private final String bootstrapperBinaryUrl;
@Inject
public OpenshiftBootstrapper(@Assisted String machineName,
@Assisted RuntimeIdentity runtimeIdentity,
@Assisted List<InstallerImpl> installers,
@Assisted OpenshiftMachine openshiftMachine,
@Named("che.infra.openshift.che_server_websocket_endpoint_base") String websocketBaseEndpoint,
@Named("che.infra.openshift.bootstrapper.binary_url") String bootstrapperBinaryUrl,
@Named("che.infra.openshift.bootstrapper.timeout_min") int bootstrappingTimeoutMinutes,
@Named("che.infra.openshift.bootstrapper.installer_timeout_sec") int installerTimeoutSeconds,
@Named("che.infra.openshift.bootstrapper.server_check_period_sec") int serverCheckPeriodSeconds,
EventService eventService) {
super(machineName, runtimeIdentity, bootstrappingTimeoutMinutes, websocketBaseEndpoint, eventService);
this.bootstrapperBinaryUrl = bootstrapperBinaryUrl;
this.machineName = machineName;
this.runtimeIdentity = runtimeIdentity;
this.installers = installers;
this.serverCheckPeriodSeconds = serverCheckPeriodSeconds;
this.installerTimeoutSeconds = installerTimeoutSeconds;
this.openshiftMachine = openshiftMachine;
}
@Override
protected void doBootstrapAsync(String installerWebsocketEndpoint,
String outputWebsocketEndpoint) throws InfrastructureException {
injectBootstrapper();
openshiftMachine.exec("sh", "-c", BOOTSTRAPPER_DIR + BOOTSTRAPPER_FILE +
" -machine-name " + machineName +
" -runtime-id " + String.format("%s:%s:%s", runtimeIdentity.getWorkspaceId(),
runtimeIdentity.getEnvName(),
runtimeIdentity.getOwner()) +
" -push-endpoint " + installerWebsocketEndpoint +
" -push-logs-endpoint " + outputWebsocketEndpoint +
" -server-check-period " + Integer.toString(serverCheckPeriodSeconds) +
" -installer-timeout " + Integer.toString(installerTimeoutSeconds) +
" -file " + BOOTSTRAPPER_DIR + CONFIG_FILE);
}
private void injectBootstrapper() throws InfrastructureException {
LOG.info("Creating folder for bootstrapper");
openshiftMachine.exec("mkdir", "-p", BOOTSTRAPPER_DIR);
LOG.info("Downloading bootstrapper binary");
openshiftMachine.exec("curl", "-o", BOOTSTRAPPER_DIR + BOOTSTRAPPER_FILE, bootstrapperBinaryUrl);
openshiftMachine.exec("chmod", "+x", BOOTSTRAPPER_DIR + BOOTSTRAPPER_FILE);
LOG.info("Creating bootstrapper config file");
openshiftMachine.exec("sh", "-c", "cat > " + BOOTSTRAPPER_DIR + CONFIG_FILE + " << 'EOF'\n"
+ GSON.toJson(installers)
+ "\nEOF");
}
}

View File

@ -0,0 +1,29 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift.bootstrapper;
import com.google.inject.assistedinject.Assisted;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.installer.server.model.impl.InstallerImpl;
import org.eclipse.che.workspace.infrastructure.openshift.OpenshiftMachine;
import java.util.List;
/**
* @author Sergii Leshchenko
*/
public interface OpenshiftBootstrapperFactory {
OpenshiftBootstrapper create(@Assisted String machineName,
@Assisted RuntimeIdentity runtimeIdentity,
@Assisted List<InstallerImpl> agents,
@Assisted OpenshiftMachine openshiftMachine);
}

View File

@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift.environment;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.openshift.api.model.Route;
import com.google.common.collect.ImmutableMap;
import java.util.HashMap;
import java.util.Map;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftEnvironment {
private Map<String, Pod> pods;
private Map<String, Service> services;
private Map<String, Route> routes;
public OpenshiftEnvironment() {
routes = new HashMap<>();
services = new HashMap<>();
pods = new HashMap<>();
}
public Map<String, Pod> getPods() {
return ImmutableMap.copyOf(pods);
}
public void addPod(Pod pod) {
pods.put(pod.getMetadata().getName(), pod);
}
public Map<String, Service> getServices() {
return services;
}
public void addService(Service service) {
services.put(service.getMetadata().getName(), service);
}
public Map<String, Route> getRoutes() {
return routes;
}
public void addRoute(Route route) {
routes.put(route.getMetadata().getName(), route);
}
}

View File

@ -0,0 +1,112 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift.environment;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.KubernetesList;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.Service;
import io.fabric8.openshift.api.model.DeploymentConfig;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.client.OpenShiftClient;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.ValidationException;
import org.eclipse.che.api.core.model.workspace.config.Environment;
import org.eclipse.che.api.core.model.workspace.config.Recipe;
import org.eclipse.che.api.workspace.server.RecipeDownloader;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.openshift.OpenshiftClientFactory;
import javax.inject.Inject;
import java.io.ByteArrayInputStream;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftEnvironmentParser {
private final OpenshiftClientFactory clientFactory;
private final RecipeDownloader recipeDownloader;
@Inject
public OpenshiftEnvironmentParser(OpenshiftClientFactory clientFactory,
RecipeDownloader recipeDownloader) {
this.clientFactory = clientFactory;
this.recipeDownloader = recipeDownloader;
}
public OpenshiftEnvironment parse(Environment environment) throws ValidationException,
InfrastructureException {
checkNotNull(environment, "Environment should not be null");
Recipe recipe = environment.getRecipe();
checkNotNull(environment.getRecipe(), "Environment recipe should not be null");
String content = getContentOfRecipe(recipe);
String contentType = recipe.getContentType();
checkNotNull(contentType, "Recipe content type should not be null");
checkNotNull(content, "Recipe content should not be null");
switch (contentType) {
case "application/x-yaml":
case "text/yaml":
case "text/x-yaml":
break;
default:
throw new ValidationException("Provided environment recipe content type '" + contentType +
"' is unsupported. Supported values are: " +
"application/x-yaml, text/yaml, text/x-yaml");
}
//TODO Implement own validation for openshift recipes, because it is OK for openshift client to load list with services only, but in our case there should be at least one pod with containers
KubernetesList list;
try (OpenShiftClient client = clientFactory.create()) {
list = client.lists().load(new ByteArrayInputStream(content.getBytes())).get();
}
OpenshiftEnvironment openshiftEnvironment = new OpenshiftEnvironment();
for (HasMetadata object : list.getItems()) {
if (object instanceof DeploymentConfig) {
// environment.addDeploymentConfig((DeploymentConfig)object);
throw new ValidationException("Supporting of deployment configs is not implemented yet.");
} else if (object instanceof Pod) {
openshiftEnvironment.addPod((Pod)object);
} else if (object instanceof Service) {
openshiftEnvironment.addService((Service)object);
} else if (object instanceof Route) {
openshiftEnvironment.addRoute((Route)object);
} else {
throw new ValidationException(String.format("Found unknown object type '%s'", object.getMetadata()));
}
}
return openshiftEnvironment;
}
private String getContentOfRecipe(Recipe environmentRecipe) throws InfrastructureException {
if (environmentRecipe.getContent() != null) {
return environmentRecipe.getContent();
} else {
try {
return recipeDownloader.getRecipe(environmentRecipe.getLocation());
} catch (ServerException e) {
throw new InfrastructureException(e.getLocalizedMessage(), e);
}
}
}
private void checkNotNull(Object object, String errorMessage) throws ValidationException {
if (object == null) {
throw new ValidationException(errorMessage);
}
}
}

View File

@ -0,0 +1,53 @@
/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.workspace.infrastructure.openshift.provision;
import io.fabric8.kubernetes.api.model.EnvVar;
import org.eclipse.che.api.core.model.workspace.config.Environment;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenshiftEnvironment;
import javax.inject.Inject;
import javax.inject.Named;
/**
* @author Sergii Leshchenko
*/
public class OpenshiftEnvironmentProvisioner {
private final String cheServerEndpoint;
@Inject
public OpenshiftEnvironmentProvisioner(@Named("che.infra.openshift.che_server_endpoint") String cheServerEndpoint) {
this.cheServerEndpoint = cheServerEndpoint;
}
public void provision(Environment envConfig,
OpenshiftEnvironment internalEnv,
RuntimeIdentity identity) throws InfrastructureException {
//TODO Add required ports to service(or create new one) and routes for agents
EnvVar workspaceIdEnv = new EnvVar("CHE_WORKSPACE_ID", identity.getWorkspaceId(), null);
EnvVar cheApiEnv = new EnvVar("CHE_API", cheServerEndpoint, null);
internalEnv.getPods()
.values()
.stream()
.flatMap(p -> p.getSpec().getContainers().stream())
.forEach(c -> {
c.getEnv().removeIf(e -> e.getName().equals("CHE_WORKSPACE_ID") || e.getName().equals("CHE_API"));
c.getEnv().add(workspaceIdEnv);
c.getEnv().add(cheApiEnv);
});
}
}

View File

@ -25,5 +25,6 @@
<name>Che Infrastructures Parent</name>
<modules>
<module>docker</module>
<module>openshift</module>
</modules>
</project>

View File

@ -141,6 +141,11 @@
<artifactId>infrastructure-docker</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che</groupId>
<artifactId>infrastructure-openshift</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che</groupId>
<artifactId>ls-csharp-agent</artifactId>

View File

@ -138,7 +138,7 @@ public abstract class RuntimeContext {
}
}
private class InternalRecipe {
protected class InternalRecipe {
private final String content;
private final String type;