diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java index 58268274f96..f11daf333a2 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInfraModule.java @@ -56,6 +56,10 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.KubernetesPluginsToolingApplier; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.PluginBrokerManager; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.SidecarToolingProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.KubernetesBrokerEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService; /** @author Sergii Leshchenko */ @@ -149,5 +153,14 @@ protected void configure() { .to(new TypeLiteral>() {}); bind(BrokerService.class); + + bind(new TypeLiteral>() {}) + .to(KubernetesBrokerEnvironmentFactory.class); + + bind(PluginBrokerManager.class) + .to(new TypeLiteral>() {}); + + bind(SidecarToolingProvisioner.class) + .to(new TypeLiteral>() {}); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java index cb5fe4da15c..74e0bb830f6 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/KubernetesInternalRuntime.java @@ -109,7 +109,7 @@ public class KubernetesInternalRuntime private final StartSynchronizer startSynchronizer; private final Set internalEnvironmentProvisioners; private final KubernetesEnvironmentProvisioner kubernetesEnvironmentProvisioner; - private final SidecarToolingProvisioner toolingProvisioner; + private final SidecarToolingProvisioner toolingProvisioner; @Inject public KubernetesInternalRuntime( @@ -129,7 +129,7 @@ public KubernetesInternalRuntime( StartSynchronizerFactory startSynchronizerFactory, Set internalEnvironmentProvisioners, KubernetesEnvironmentProvisioner kubernetesEnvironmentProvisioner, - SidecarToolingProvisioner toolingProvisioner, + SidecarToolingProvisioner toolingProvisioner, @Assisted KubernetesRuntimeContext context, @Assisted KubernetesNamespace namespace, @Assisted List warnings) { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java index 04bd54a7017..f0b9196d556 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/PluginBrokerManager.java @@ -12,25 +12,21 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins; import com.google.common.annotations.Beta; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; import javax.inject.Inject; -import javax.inject.Named; 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.provision.env.AgentAuthEnableEnvVarProvider; -import org.eclipse.che.api.workspace.server.spi.provision.env.MachineTokenEnvVarProvider; import org.eclipse.che.api.workspace.server.wsplugins.model.ChePlugin; import org.eclipse.che.api.workspace.server.wsplugins.model.PluginMeta; -import org.eclipse.che.commons.lang.NameGenerator; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesEnvironmentProvisioner; 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.namespace.KubernetesNamespaceFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.pvc.WorkspaceVolumesStrategy; -import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.DeliverMetas; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.DeployBroker; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.ListenBrokerEvents; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.PrepareStorage; @@ -45,47 +41,26 @@ * @author Oleksandr Garagatyi */ @Beta -public class PluginBrokerManager { - - private static final String PVC_CLAIM_PROJECTS = "claim-che-workspace"; - private static final String CONFIG_MAP_NAME_SUFFIX = "broker-config-map"; - private static final String BROKER_VOLUME = "broker-config-volume"; - private static final String CONF_FOLDER = "/broker-config"; - private static final String CONFIG_FILE = "config.json"; +public class PluginBrokerManager { private final KubernetesNamespaceFactory factory; private final EventService eventService; private final WorkspaceVolumesStrategy volumesStrategy; - private final AgentAuthEnableEnvVarProvider authEnableEnvVarProvider; - private final MachineTokenEnvVarProvider machineTokenEnvVarProvider; - private final String pvcName; - private final String pvcQuantity; - private final String pvcAccessMode; - private final String cheWebsocketEndpoint; - private final String pluginBrokerImage; + private final BrokerEnvironmentFactory brokerEnvironmentConfig; + private final KubernetesEnvironmentProvisioner environmentProvisioner; @Inject public PluginBrokerManager( KubernetesNamespaceFactory factory, EventService eventService, + KubernetesEnvironmentProvisioner environmentProvisioner, WorkspaceVolumesStrategy volumesStrategy, - AgentAuthEnableEnvVarProvider authEnableEnvVarProvider, - MachineTokenEnvVarProvider machineTokenEnvVarProvider, - @Named("che.infra.kubernetes.pvc.name") String pvcName, - @Named("che.infra.kubernetes.pvc.quantity") String pvcQuantity, - @Named("che.infra.kubernetes.pvc.access_mode") String pvcAccessMode, - @Named("che.websocket.endpoint") String cheWebsocketEndpoint, - @Named("che.workspace.plugin_broker.image") String pluginBrokerImage) { + BrokerEnvironmentFactory brokerEnvironmentConfig) { this.factory = factory; this.eventService = eventService; this.volumesStrategy = volumesStrategy; - this.authEnableEnvVarProvider = authEnableEnvVarProvider; - this.machineTokenEnvVarProvider = machineTokenEnvVarProvider; - this.pvcName = pvcName; - this.pvcQuantity = pvcQuantity; - this.pvcAccessMode = pvcAccessMode; - this.cheWebsocketEndpoint = cheWebsocketEndpoint; - this.pluginBrokerImage = pluginBrokerImage; + this.brokerEnvironmentConfig = brokerEnvironmentConfig; + this.environmentProvisioner = environmentProvisioner; } /** @@ -95,71 +70,38 @@ public PluginBrokerManager( *

This API is in Beta and is subject to changes or removal. */ @Beta - public List getTooling( - RuntimeIdentity runtimeID, - Collection pluginsMeta, - KubernetesEnvironment environment) + public List getTooling(RuntimeIdentity runtimeID, Collection pluginsMeta) throws InfrastructureException { String workspaceId = runtimeID.getWorkspaceId(); - CompletableFuture> toolingFuture = new CompletableFuture<>(); KubernetesNamespace kubernetesNamespace = factory.create(workspaceId); + E brokerEnvironment = brokerEnvironmentConfig.create(pluginsMeta, runtimeID); - String configMapName = generateUniqueConfigMapName(); + environmentProvisioner.provision(brokerEnvironment, runtimeID); ListenBrokerEvents listenBrokerEvents = getListenEventPhase(workspaceId, toolingFuture); - PrepareStorage prepareStorage = getPrepareStoragePhase(workspaceId, environment); - DeliverMetas deliverMetas = - getDeliverPhaseMetas(kubernetesNamespace, pluginsMeta, configMapName); + PrepareStorage prepareStorage = getPrepareStoragePhase(workspaceId, brokerEnvironment); WaitBrokerResult waitBrokerResult = getWaitBrokerPhase(toolingFuture); - DeployBroker deployBroker = getDeployBrokerPhase(kubernetesNamespace, runtimeID, configMapName); + DeployBroker deployBroker = getDeployBrokerPhase(kubernetesNamespace, brokerEnvironment); - listenBrokerEvents - .then(prepareStorage) - .then(deliverMetas) - .then(deployBroker) - .then(waitBrokerResult); + listenBrokerEvents.then(prepareStorage).then(deployBroker).then(waitBrokerResult); return listenBrokerEvents.execute(); } - private String generateUniqueConfigMapName() { - return NameGenerator.generate(CONFIG_MAP_NAME_SUFFIX, 6); - } - private ListenBrokerEvents getListenEventPhase( String workspaceId, CompletableFuture> toolingFuture) { return new ListenBrokerEvents(workspaceId, toolingFuture, eventService); } private PrepareStorage getPrepareStoragePhase( - String workspaceId, KubernetesEnvironment environment) { - return new PrepareStorage( - workspaceId, environment, volumesStrategy, pvcName, pvcAccessMode, pvcQuantity); - } - - private DeliverMetas getDeliverPhaseMetas( - KubernetesNamespace kubernetesNamespace, - Collection pluginsMeta, - String configMapName) { - return new DeliverMetas(kubernetesNamespace, pluginsMeta, CONFIG_FILE, configMapName); + String workspaceId, KubernetesEnvironment brokerEnvironment) { + return new PrepareStorage(workspaceId, brokerEnvironment, volumesStrategy); } private DeployBroker getDeployBrokerPhase( - KubernetesNamespace kubernetesNamespace, RuntimeIdentity runtimeId, String configMapName) - throws InfrastructureException { - return new DeployBroker( - kubernetesNamespace, - runtimeId.getWorkspaceId(), - cheWebsocketEndpoint, - CONF_FOLDER, - CONFIG_FILE, - PVC_CLAIM_PROJECTS, - BROKER_VOLUME, - configMapName, - pluginBrokerImage, - Arrays.asList( - authEnableEnvVarProvider.get(runtimeId), machineTokenEnvVarProvider.get(runtimeId))); + KubernetesNamespace kubernetesNamespace, KubernetesEnvironment brokerEnvironment) { + return new DeployBroker(kubernetesNamespace, brokerEnvironment); } private WaitBrokerResult getWaitBrokerPhase(CompletableFuture> toolingFuture) { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java index 685b21b9412..1e7b3983d35 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/SidecarToolingProvisioner.java @@ -31,25 +31,24 @@ * @author Oleksandr Garagatyi */ @Beta -public class SidecarToolingProvisioner { +public class SidecarToolingProvisioner { private final Map workspaceNextAppliers; private final PluginMetaRetriever pluginMetaRetriever; - private final PluginBrokerManager pluginBrokerManager; + private final PluginBrokerManager pluginBrokerManager; @Inject public SidecarToolingProvisioner( Map workspaceNextAppliers, PluginMetaRetriever pluginMetaRetriever, - PluginBrokerManager pluginBrokerManager) { + PluginBrokerManager pluginBrokerManager) { this.workspaceNextAppliers = ImmutableMap.copyOf(workspaceNextAppliers); this.pluginMetaRetriever = pluginMetaRetriever; this.pluginBrokerManager = pluginBrokerManager; } @Beta - public void provision(RuntimeIdentity id, KubernetesEnvironment environment) - throws InfrastructureException { + public void provision(RuntimeIdentity id, E environment) throws InfrastructureException { Collection pluginsMeta = pluginMetaRetriever.get(environment.getAttributes()); if (pluginsMeta.isEmpty()) { @@ -63,7 +62,7 @@ public void provision(RuntimeIdentity id, KubernetesEnvironment environment) "Sidecar tooling configuration is not supported with recipe type " + recipeType); } - List chePlugins = pluginBrokerManager.getTooling(id, pluginsMeta, environment); + List chePlugins = pluginBrokerManager.getTooling(id, pluginsMeta); pluginsApplier.apply(environment, chePlugins); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/BrokerEnvironmentFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/BrokerEnvironmentFactory.java new file mode 100644 index 00000000000..3661397ab58 --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/BrokerEnvironmentFactory.java @@ -0,0 +1,176 @@ +/* + * 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.wsplugins.brokerphases; + +import static java.util.Collections.singletonMap; +import static java.util.stream.Collectors.toList; + +import com.google.common.annotations.Beta; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.ContainerBuilder; +import io.fabric8.kubernetes.api.model.EnvVar; +import io.fabric8.kubernetes.api.model.EnvVarBuilder; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; +import io.fabric8.kubernetes.api.model.Quantity; +import io.fabric8.kubernetes.api.model.VolumeBuilder; +import io.fabric8.kubernetes.api.model.VolumeMount; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import javax.inject.Inject; +import javax.inject.Named; +import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; +import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl; +import org.eclipse.che.api.workspace.server.spi.InfrastructureException; +import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; +import org.eclipse.che.api.workspace.server.spi.provision.env.AgentAuthEnableEnvVarProvider; +import org.eclipse.che.api.workspace.server.spi.provision.env.MachineTokenEnvVarProvider; +import org.eclipse.che.api.workspace.server.wsplugins.model.PluginMeta; +import org.eclipse.che.commons.lang.NameGenerator; +import org.eclipse.che.commons.lang.Pair; +import org.eclipse.che.workspace.infrastructure.kubernetes.Names; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; + +/** + * Creates {@link KubernetesEnvironment} with everything needed to deploy Plugin broker. + * + *

It has to be extended to be used in the kubernetes or openshift infrastructures because of the + * usage of a complex inheritance between components of these infrastructures. + * + *

This API is in Beta and is subject to changes or removal. + * + * @author Oleksandr Garagatyi + */ +@Beta +public abstract class BrokerEnvironmentFactory { + + private static final String CONFIG_MAP_NAME_SUFFIX = "broker-config-map"; + private static final String BROKER_VOLUME = "broker-config-volume"; + private static final String CONF_FOLDER = "/broker-config"; + private static final String CONFIG_FILE = "config.json"; + private static final String CONTAINER_NAME = "broker"; + private static final String PLUGINS_VOLUME_NAME = "plugins"; + private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); + + private final String cheWebsocketEndpoint; + private final String pluginBrokerImage; + private final AgentAuthEnableEnvVarProvider authEnableEnvVarProvider; + private final MachineTokenEnvVarProvider machineTokenEnvVarProvider; + + @Inject + public BrokerEnvironmentFactory( + @Named("che.websocket.endpoint") String cheWebsocketEndpoint, + @Named("che.workspace.plugin_broker.image") String pluginBrokerImage, + AgentAuthEnableEnvVarProvider authEnableEnvVarProvider, + MachineTokenEnvVarProvider machineTokenEnvVarProvider) { + this.cheWebsocketEndpoint = cheWebsocketEndpoint; + this.pluginBrokerImage = pluginBrokerImage; + this.authEnableEnvVarProvider = authEnableEnvVarProvider; + this.machineTokenEnvVarProvider = machineTokenEnvVarProvider; + } + + /** + * Creates {@link KubernetesEnvironment} with everything needed to deploy Plugin broker. + * + * @param pluginsMeta meta info of plugins that needs to be resolved by the broker + * @param runtimeID ID of the runtime the broker would be started + * @return kubernetes environment (or its extension) with the Plugin broker objects + */ + public E create(Collection pluginsMeta, RuntimeIdentity runtimeID) + throws InfrastructureException { + String workspaceId = runtimeID.getWorkspaceId(); + + String configMapName = generateUniqueConfigMapName(); + String podName = "che-plugin-broker"; + List> envVars = + Arrays.asList( + authEnableEnvVarProvider.get(runtimeID), machineTokenEnvVarProvider.get(runtimeID)); + Pod pod = newPod(podName, workspaceId, configMapName, envVars); + String machineName = Names.machineName(pod, pod.getSpec().getContainers().get(0)); + InternalMachineConfig machine = new InternalMachineConfig(); + machine.getVolumes().put(PLUGINS_VOLUME_NAME, new VolumeImpl().withPath("/plugins")); + + ConfigMap configMap = newConfigMap(configMapName, pluginsMeta); + return doCreate(machineName, machine, configMapName, configMap, pod); + } + + /** Needed to implement this component in both - Kubernetes and Openshift infrastructures. */ + protected abstract E doCreate( + String machineName, + InternalMachineConfig machine, + String configMapName, + ConfigMap configMap, + Pod pod); + + private String generateUniqueConfigMapName() { + return NameGenerator.generate(CONFIG_MAP_NAME_SUFFIX, 6); + } + + private Pod newPod( + String podName, + String workspaceId, + String configMapName, + List> envVars) { + final Container container = + new ContainerBuilder() + .withName(CONTAINER_NAME) + .withImage(pluginBrokerImage) + .withArgs( + "-metas", + CONF_FOLDER + "/" + CONFIG_FILE, + "-push-endpoint", + cheWebsocketEndpoint, + "-workspace-id", + workspaceId) + .withImagePullPolicy("Always") + .withVolumeMounts(new VolumeMount(CONF_FOLDER + "/", BROKER_VOLUME, true, null)) + .withEnv(envVars.stream().map(this::asEnvVar).collect(toList())) + .withNewResources() + .withLimits(singletonMap("memory", new Quantity("250Mi"))) + .endResources() + .build(); + return new PodBuilder() + .withNewMetadata() + .withName(podName) + .endMetadata() + .withNewSpec() + .withContainers(container) + .withVolumes( + new VolumeBuilder() + .withName(BROKER_VOLUME) + .withNewConfigMap() + .withName(configMapName) + .endConfigMap() + .build()) + .withRestartPolicy("Never") + .endSpec() + .build(); + } + + private ConfigMap newConfigMap(String configMapName, Collection pluginsMetas) { + return new ConfigMapBuilder() + .withNewMetadata() + .withName(configMapName) + .endMetadata() + .withData(singletonMap(CONFIG_FILE, GSON.toJson(pluginsMetas))) + .build(); + } + + private EnvVar asEnvVar(Pair envVar) { + return new EnvVarBuilder().withName(envVar.first).withValue(envVar.second).build(); + } +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeliverMetas.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeliverMetas.java deleted file mode 100644 index c3a3b7dbb9e..00000000000 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeliverMetas.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.wsplugins.brokerphases; - -import static org.slf4j.LoggerFactory.getLogger; - -import com.google.common.annotations.Beta; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.ConfigMapBuilder; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.che.api.workspace.server.spi.InfrastructureException; -import org.eclipse.che.api.workspace.server.wsplugins.model.ChePlugin; -import org.eclipse.che.api.workspace.server.wsplugins.model.PluginMeta; -import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; -import org.slf4j.Logger; - -/** - * Creates config map that can inject Che tooling plugins meta files into a Che plugin broker in a - * workspace. Then calls next {@link BrokerPhase} and removes config map after next phase completes. - * - *

This API is in Beta and is subject to changes or removal. - * - * @author Oleksandr Garagatyi - */ -@Beta -public class DeliverMetas extends BrokerPhase { - - private static final Logger LOG = getLogger(DeliverMetas.class); - private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create(); - - private final KubernetesNamespace kubernetesNamespace; - private final Collection pluginsMeta; - private final String configFile; - private final String configMapName; - - public DeliverMetas( - KubernetesNamespace kubernetesNamespace, - Collection pluginsMeta, - String configFile, - String configMapName) { - this.kubernetesNamespace = kubernetesNamespace; - this.pluginsMeta = pluginsMeta; - this.configFile = configFile; - this.configMapName = configMapName; - } - - @Override - public List execute() throws InfrastructureException { - try { - kubernetesNamespace.configMaps().create(newConfigMap(pluginsMeta)); - - return nextPhase.execute(); - } finally { - try { - kubernetesNamespace.configMaps().delete(); - } catch (InfrastructureException ex) { - LOG.error( - "Broker deployment config map removal failed. Error: " + ex.getLocalizedMessage(), ex); - } - } - } - - private ConfigMap newConfigMap(Collection pluginsMetas) { - Map initConfigMapData = new HashMap<>(); - initConfigMapData.put(configFile, stringYaml(pluginsMetas)); - - return new ConfigMapBuilder() - .withNewMetadata() - .withName(configMapName) - .endMetadata() - .withData(initConfigMapData) - .build(); - } - - private String stringYaml(Collection pluginsMetas) { - return GSON.toJson(pluginsMetas); - } -} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java index cd49632cb3e..1bf7c9dda2e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/DeployBroker.java @@ -11,26 +11,15 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases; -import static java.util.Collections.singletonMap; -import static java.util.stream.Collectors.toList; -import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.newVolume; -import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.newVolumeMount; import static org.slf4j.LoggerFactory.getLogger; import com.google.common.annotations.Beta; -import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.ContainerBuilder; -import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.EnvVarBuilder; +import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.Pod; -import io.fabric8.kubernetes.api.model.PodBuilder; -import io.fabric8.kubernetes.api.model.Quantity; -import io.fabric8.kubernetes.api.model.VolumeBuilder; -import io.fabric8.kubernetes.api.model.VolumeMount; import java.util.List; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.wsplugins.model.ChePlugin; -import org.eclipse.che.commons.lang.Pair; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesDeployments; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespace; import org.slf4j.Logger; @@ -48,99 +37,40 @@ public class DeployBroker extends BrokerPhase { private static final Logger LOG = getLogger(DeployBroker.class); - private final String workspaceId; - private final String cheWebsocketEndpoint; - private final String confFolder; - private final String configFile; - private final String pvcClaimProjects; - private final String brokerVolume; - private final String configMapName; - private final String pluginBrokerImage; - private final KubernetesNamespace kubernetesNamespace; - private final List envVars; + private final KubernetesNamespace namespace; + private final KubernetesEnvironment brokerEnvironment; - public DeployBroker( - KubernetesNamespace kubernetesNamespace, - String workspaceId, - String cheWebsocketEndpoint, - String confFolder, - String configFile, - String pvcClaimProjects, - String brokerVolume, - String configMapName, - String pluginBrokerImage, - List> envVars) { - this.kubernetesNamespace = kubernetesNamespace; - this.workspaceId = workspaceId; - this.cheWebsocketEndpoint = cheWebsocketEndpoint; - this.confFolder = confFolder; - this.configFile = configFile; - this.pvcClaimProjects = pvcClaimProjects; - this.brokerVolume = brokerVolume; - this.configMapName = configMapName; - this.pluginBrokerImage = pluginBrokerImage; - this.envVars = envVars.stream().map(this::asEnvVar).collect(toList()); + public DeployBroker(KubernetesNamespace namespace, KubernetesEnvironment brokerEnvironment) { + this.namespace = namespace; + this.brokerEnvironment = brokerEnvironment; } @Override public List execute() throws InfrastructureException { - final String podName = "che-plugin-broker-" + workspaceId; - final Pod pod = newPod(podName, workspaceId); - KubernetesDeployments deployments = kubernetesNamespace.deployments(); + KubernetesDeployments deployments = namespace.deployments(); try { - deployments.create(pod); + // Creates config map that can inject Che tooling plugins meta files into a Che plugin + // broker in a workspace. + for (ConfigMap configMap : brokerEnvironment.getConfigMaps().values()) { + namespace.configMaps().create(configMap); + } + for (Pod toCreate : brokerEnvironment.getPods().values()) { + deployments.deploy(toCreate); + } return nextPhase.execute(); } finally { try { - deployments.delete(podName); + deployments.delete(); } catch (InfrastructureException e) { LOG.error("Broker deployment removal failed. Error: " + e.getLocalizedMessage(), e); } + try { + namespace.configMaps().delete(); + } catch (InfrastructureException ex) { + LOG.error( + "Broker deployment config map removal failed. Error: " + ex.getLocalizedMessage(), ex); + } } } - - private Pod newPod(String podName, String workspaceId) { - final Container container = - new ContainerBuilder() - .withName(podName) - .withImage(pluginBrokerImage) - .withArgs( - "-metas", - confFolder + "/" + configFile, - "-push-endpoint", - cheWebsocketEndpoint, - "-workspace-id", - workspaceId) - .withImagePullPolicy("Always") - .withVolumeMounts( - newVolumeMount(pvcClaimProjects, "/plugins", workspaceId + "/plugins"), - new VolumeMount(confFolder + "/", brokerVolume, true, null)) - .withEnv(envVars) - .withNewResources() - .withLimits(singletonMap("memory", new Quantity("250Mi"))) - .endResources() - .build(); - return new PodBuilder() - .withNewMetadata() - .withName(podName) - .endMetadata() - .withNewSpec() - .withContainers(container) - .withVolumes( - newVolume(pvcClaimProjects, pvcClaimProjects), - new VolumeBuilder() - .withName(brokerVolume) - .withNewConfigMap() - .withName(configMapName) - .endConfigMap() - .build()) - .withRestartPolicy("Never") - .endSpec() - .build(); - } - - private EnvVar asEnvVar(Pair envVar) { - return new EnvVarBuilder().withName(envVar.first).withValue(envVar.second).build(); - } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/KubernetesBrokerEnvironmentFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/KubernetesBrokerEnvironmentFactory.java new file mode 100644 index 00000000000..f89268986ad --- /dev/null +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/KubernetesBrokerEnvironmentFactory.java @@ -0,0 +1,63 @@ +/* + * 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.wsplugins.brokerphases; + +import static java.util.Collections.singletonMap; + +import com.google.common.annotations.Beta; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.Pod; +import javax.inject.Inject; +import javax.inject.Named; +import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; +import org.eclipse.che.api.workspace.server.spi.provision.env.AgentAuthEnableEnvVarProvider; +import org.eclipse.che.api.workspace.server.spi.provision.env.MachineTokenEnvVarProvider; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; + +/** + * Extends {@link BrokerEnvironmentFactory} to be used in the kubernetes infrastructure. + * + *

This API is in Beta and is subject to changes or removal. + * + * @author Oleksandr Garagatyi + */ +@Beta +public class KubernetesBrokerEnvironmentFactory + extends BrokerEnvironmentFactory { + + @Inject + public KubernetesBrokerEnvironmentFactory( + @Named("che.websocket.endpoint") String cheWebsocketEndpoint, + @Named("che.workspace.plugin_broker.image") String pluginBrokerImage, + AgentAuthEnableEnvVarProvider authEnableEnvVarProvider, + MachineTokenEnvVarProvider machineTokenEnvVarProvider) { + super( + cheWebsocketEndpoint, + pluginBrokerImage, + authEnableEnvVarProvider, + machineTokenEnvVarProvider); + } + + @Override + protected KubernetesEnvironment doCreate( + String machineName, + InternalMachineConfig machine, + String configMapName, + ConfigMap configMap, + Pod pod) { + return KubernetesEnvironment.builder() + .setConfigMaps(singletonMap(configMapName, configMap)) + .setMachines(singletonMap(machineName, machine)) + .setPods(singletonMap(pod.getMetadata().getName(), pod)) + .build(); + } +} diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java index dbac0b814f3..e766afe9a19 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/brokerphases/PrepareStorage.java @@ -11,10 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases; -import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.newPVC; - import com.google.common.annotations.Beta; -import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import java.util.List; import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.api.workspace.server.wsplugins.model.ChePlugin; @@ -32,32 +29,21 @@ public class PrepareStorage extends BrokerPhase { private final String workspaceId; - private final KubernetesEnvironment environment; + private final KubernetesEnvironment brokerEnvironment; private final WorkspaceVolumesStrategy volumesStrategy; - private final String pvcName; - private final String pvcAccessMode; - private final String pvcQuantity; public PrepareStorage( String workspaceId, - KubernetesEnvironment environment, - WorkspaceVolumesStrategy volumesStrategy, - String pvcName, - String pvcAccessMode, - String pvcQuantity) { + KubernetesEnvironment brokerEnvironment, + WorkspaceVolumesStrategy volumesStrategy) { this.workspaceId = workspaceId; - this.environment = environment; + this.brokerEnvironment = brokerEnvironment; this.volumesStrategy = volumesStrategy; - this.pvcName = pvcName; - this.pvcAccessMode = pvcAccessMode; - this.pvcQuantity = pvcQuantity; } @Override public List execute() throws InfrastructureException { - final PersistentVolumeClaim pvc = newPVC(pvcName, pvcAccessMode, pvcQuantity); - environment.getPersistentVolumeClaims().put(pvcName, pvc); - volumesStrategy.prepare(environment, workspaceId); + volumesStrategy.prepare(brokerEnvironment, workspaceId); return nextPhase.execute(); } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java index 4c466d3c10f..4b5f4240d93 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInfraModule.java @@ -29,6 +29,7 @@ import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironment; import org.eclipse.che.workspace.infrastructure.docker.environment.dockerimage.DockerImageEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesClientTermination; +import org.eclipse.che.workspace.infrastructure.kubernetes.KubernetesEnvironmentProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.StartSynchronizerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.bootstrapper.KubernetesBootstrapperFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.cache.jpa.JpaKubernetesRuntimeCacheModule; @@ -47,12 +48,16 @@ import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposerFactoryProvider; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.KubernetesPluginsToolingApplier; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.PluginBrokerManager; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.SidecarToolingProvisioner; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.events.BrokerService; import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironmentFactory; import org.eclipse.che.workspace.infrastructure.openshift.project.OpenShiftProjectFactory; import org.eclipse.che.workspace.infrastructure.openshift.project.RemoveProjectOnWorkspaceRemove; import org.eclipse.che.workspace.infrastructure.openshift.server.OpenShiftExternalServerExposer; +import org.eclipse.che.workspace.infrastructure.openshift.wsplugins.brokerphases.OpenshiftBrokerEnvironmentFactory; /** @author Sergii Leshchenko */ public class OpenShiftInfraModule extends AbstractModule { @@ -118,5 +123,17 @@ protected void configure() { .to(new TypeLiteral>() {}); bind(BrokerService.class); + + bind(new TypeLiteral>() {}) + .to(OpenshiftBrokerEnvironmentFactory.class); + + bind(PluginBrokerManager.class) + .to(new TypeLiteral>() {}); + + bind(SidecarToolingProvisioner.class) + .to(new TypeLiteral>() {}); + + bind(new TypeLiteral>() {}) + .to(OpenShiftEnvironmentProvisioner.class); } } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/wsplugins/brokerphases/OpenshiftBrokerEnvironmentFactory.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/wsplugins/brokerphases/OpenshiftBrokerEnvironmentFactory.java new file mode 100644 index 00000000000..c36df7df5e6 --- /dev/null +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/wsplugins/brokerphases/OpenshiftBrokerEnvironmentFactory.java @@ -0,0 +1,65 @@ +/* + * 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.openshift.wsplugins.brokerphases; + +import static java.util.Collections.singletonMap; + +import com.google.common.annotations.Beta; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.Pod; +import javax.inject.Inject; +import javax.inject.Named; +import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig; +import org.eclipse.che.api.workspace.server.spi.provision.env.AgentAuthEnableEnvVarProvider; +import org.eclipse.che.api.workspace.server.spi.provision.env.MachineTokenEnvVarProvider; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory; +import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.KubernetesBrokerEnvironmentFactory; +import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment; + +/** + * Extends {@link KubernetesBrokerEnvironmentFactory} to be used in the openshift infrastructure. + * + *

This API is in Beta and is subject to changes or removal. + * + * @author Oleksandr Garagatyi + */ +@Beta +public class OpenshiftBrokerEnvironmentFactory + extends BrokerEnvironmentFactory { + + @Inject + public OpenshiftBrokerEnvironmentFactory( + @Named("che.websocket.endpoint") String cheWebsocketEndpoint, + @Named("che.workspace.plugin_broker.image") String pluginBrokerImage, + AgentAuthEnableEnvVarProvider authEnableEnvVarProvider, + MachineTokenEnvVarProvider machineTokenEnvVarProvider) { + super( + cheWebsocketEndpoint, + pluginBrokerImage, + authEnableEnvVarProvider, + machineTokenEnvVarProvider); + } + + @Override + protected OpenShiftEnvironment doCreate( + String machineName, + InternalMachineConfig machine, + String configMapName, + ConfigMap configMap, + Pod pod) { + return OpenShiftEnvironment.builder() + .setConfigMaps(singletonMap(configMapName, configMap)) + .setMachines(singletonMap(machineName, machine)) + .setPods(singletonMap(pod.getMetadata().getName(), pod)) + .build(); + } +}