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 960eb249e1..d4bc5defdc 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 @@ -21,14 +21,18 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Service; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.extensions.Ingress; import io.fabric8.kubernetes.client.Watcher.Action; import io.opentracing.Span; import io.opentracing.Tracer; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -642,12 +646,14 @@ public class KubernetesInternalRuntime // namespace.pods().watch(new AbnormalStopHandler()); namespace.deployments().watchEvents(new MachineLogsPublisher()); if (unrecoverableEventListenerFactory.isConfigured()) { - Map pods = getContext().getEnvironment().getPods(); + Set toWatch = new HashSet<>(); + KubernetesEnvironment environment = getContext().getEnvironment(); + toWatch.addAll(environment.getPodsCopy().keySet()); + toWatch.addAll(environment.getDeploymentsCopy().keySet()); namespace .deployments() .watchEvents( - unrecoverableEventListenerFactory.create( - pods.keySet(), this::handleUnrecoverableEvent)); + unrecoverableEventListenerFactory.create(toWatch, this::handleUnrecoverableEvent)); } final KubernetesServerResolver serverResolver = @@ -713,39 +719,57 @@ public class KubernetesInternalRuntime final Map machineConfigs = environment.getMachines(); final String workspaceId = getContext().getIdentity().getWorkspaceId(); LOG.debug("Begin pods creation for workspace '{}'", workspaceId); - for (Pod toCreate : environment.getPods().values()) { - startTracingContainersStartup(toCreate); + for (Pod toCreate : environment.getPodsCopy().values()) { + startTracingContainersStartup(toCreate.getSpec(), toCreate.getMetadata()); + ObjectMeta toCreateMeta = toCreate.getMetadata(); final Pod createdPod = namespace.deployments().deploy(toCreate); - LOG.debug( - "Creating pod '{}' in workspace '{}'", toCreate.getMetadata().getName(), workspaceId); - final ObjectMeta podMetadata = createdPod.getMetadata(); - for (Container container : createdPod.getSpec().getContainers()) { - String machineName = Names.machineName(toCreate, container); - - LOG.debug("Creating machine '{}' in workspace '{}'", machineName, workspaceId); - machines.put( - getContext().getIdentity(), - new KubernetesMachineImpl( - workspaceId, - machineName, - podMetadata.getName(), - container.getName(), - MachineStatus.STARTING, - machineConfigs.get(machineName).getAttributes(), - serverResolver.resolve(machineName))); - eventPublisher.sendStartingEvent(machineName, getContext().getIdentity()); - } + LOG.debug("Creating pod '{}' in workspace '{}'", toCreateMeta.getName(), workspaceId); + startMachines(createdPod, toCreateMeta, machineConfigs, serverResolver); + } + for (Deployment toCreate : environment.getDeploymentsCopy().values()) { + PodTemplateSpec template = toCreate.getSpec().getTemplate(); + startTracingContainersStartup(template.getSpec(), template.getMetadata()); + ObjectMeta toCreateMeta = toCreate.getMetadata(); + final Pod createdPod = namespace.deployments().deploy(toCreate); + LOG.debug("Creating deployment '{}' in workspace '{}'", toCreateMeta.getName(), workspaceId); + startMachines(createdPod, toCreateMeta, machineConfigs, serverResolver); } LOG.debug("Pods creation finished in workspace '{}'", workspaceId); } - private void startTracingContainersStartup(Pod pod) { + /** Puts createdPod in the {@code machines} map and sends the starting event for this machine */ + public void startMachines( + Pod createdPod, + ObjectMeta toCreateMeta, + Map machineConfigs, + KubernetesServerResolver serverResolver) + throws InfrastructureException { + final String workspaceId = getContext().getIdentity().getWorkspaceId(); + for (Container container : createdPod.getSpec().getContainers()) { + String machineName = Names.machineName(toCreateMeta, container); + + LOG.debug("Creating machine '{}' in workspace '{}'", machineName, workspaceId); + machines.put( + getContext().getIdentity(), + new KubernetesMachineImpl( + workspaceId, + machineName, + createdPod.getMetadata().getName(), + container.getName(), + MachineStatus.STARTING, + machineConfigs.get(machineName).getAttributes(), + serverResolver.resolve(machineName))); + eventPublisher.sendStartingEvent(machineName, getContext().getIdentity()); + } + } + + private void startTracingContainersStartup(PodSpec podSpec, ObjectMeta podMeta) { if (tracer == null) { return; } - for (Container container : pod.getSpec().getContainers()) { - String machineName = Names.machineName(pod, container); + for (Container container : podSpec.getContainers()) { + String machineName = Names.machineName(podMeta, container); machineStartupTraces.put( machineName, diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Names.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Names.java index 1206f7cd23..99be943294 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Names.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/Names.java @@ -16,9 +16,11 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.MACHINE_NAME_ANNOTATION_FMT; import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Pod; import java.util.Map; import org.eclipse.che.commons.lang.NameGenerator; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Helps to work with Kubernetes objects names. @@ -45,7 +47,15 @@ public class Names { * */ public static String machineName(Pod pod, Container container) { - final Map annotations = pod.getMetadata().getAnnotations(); + return machineName(pod.getMetadata(), container); + } + + public static String machineName(PodData podData, Container container) { + return machineName(podData.getMetadata(), container); + } + + public static String machineName(ObjectMeta podMeta, Container container) { + final Map annotations = podMeta.getAnnotations(); final String machineName; final String containerName = container.getName(); if (annotations != null @@ -55,11 +65,11 @@ public class Names { } final String originalPodName; - final Map labels = pod.getMetadata().getLabels(); + final Map labels = podMeta.getLabels(); if (labels != null && (originalPodName = labels.get(CHE_ORIGINAL_NAME_LABEL)) != null) { return originalPodName + '/' + containerName; } - return pod.getMetadata().getName() + '/' + containerName; + return podMeta.getName() + '/' + containerName; } /** Return pod name that will be unique for a whole namespace. */ diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironment.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironment.java index bd8f5d8206..525d895670 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironment.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironment.java @@ -11,11 +11,16 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.environment; +import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Service; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.extensions.Ingress; import java.util.ArrayList; import java.util.HashMap; @@ -37,6 +42,14 @@ public class KubernetesEnvironment extends InternalEnvironment { public static final String TYPE = "kubernetes"; private final Map pods; + private final Map deployments; + /** + * Stores abstracted spec and meta from either a deployment or pod. + * + *

{@link PodData} + */ + private final Map podData; + private final Map services; private final Map ingresses; private final Map persistentVolumeClaims; @@ -61,7 +74,9 @@ public class KubernetesEnvironment extends InternalEnvironment { public KubernetesEnvironment(KubernetesEnvironment k8sEnv) { this( k8sEnv, - k8sEnv.getPods(), + k8sEnv.getPodsCopy(), + k8sEnv.getDeploymentsCopy(), + k8sEnv.getPodData(), k8sEnv.getServices(), k8sEnv.getIngresses(), k8sEnv.getPersistentVolumeClaims(), @@ -72,6 +87,8 @@ public class KubernetesEnvironment extends InternalEnvironment { protected KubernetesEnvironment( InternalEnvironment internalEnvironment, Map pods, + Map deployments, + Map podData, Map services, Map ingresses, Map persistentVolumeClaims, @@ -80,6 +97,8 @@ public class KubernetesEnvironment extends InternalEnvironment { super(internalEnvironment); setType(TYPE); this.pods = pods; + this.deployments = deployments; + this.podData = podData; this.services = services; this.ingresses = ingresses; this.persistentVolumeClaims = persistentVolumeClaims; @@ -92,6 +111,8 @@ public class KubernetesEnvironment extends InternalEnvironment { Map machines, List warnings, Map pods, + Map deployments, + Map podData, Map services, Map ingresses, Map persistentVolumeClaims, @@ -100,6 +121,8 @@ public class KubernetesEnvironment extends InternalEnvironment { super(internalRecipe, machines, warnings); setType(TYPE); this.pods = pods; + this.deployments = deployments; + this.podData = podData; this.services = services; this.ingresses = ingresses; this.persistentVolumeClaims = persistentVolumeClaims; @@ -112,9 +135,43 @@ public class KubernetesEnvironment extends InternalEnvironment { return (KubernetesEnvironment) super.setType(type); } - /** Returns pods that should be created when environment starts. */ - public Map getPods() { - return pods; + /** + * Returns pods that should be created when environment starts. + * + *

Note: This map should not be changed, as it will only return pods and not + * deployments. If objects in the map need to be changed, see {@link #getPodData()} + */ + public Map getPodsCopy() { + return ImmutableMap.copyOf(pods); + } + + /** + * Returns deployments that should be created when environment starts. + * + *

Note: This map should not be changed. If objects in the map need to be changed, see + * {@link #getPodData()} + */ + public Map getDeploymentsCopy() { + return ImmutableMap.copyOf(deployments); + } + + /** + * Returns {@link PodData} representing the metadata and pod spec of objects (pods or deployments) + * that should be created when environment starts. The data returned by this method represents all + * deployment and pod objects that form the workspace, and should be used when provisioning or + * performing any action that needs to see every object in the environment. + */ + public Map getPodData() { + return ImmutableMap.copyOf(podData); + } + + /** + * Add a pod to the current environment. This method is necessary as the map returned by {@link + * #getPodsCopy()} is a copy. This method also adds the relevant data to {@link #getPodData()}. + */ + public void addPod(String key, Pod pod) { + pods.put(key, pod); + podData.put(key, new PodData(pod.getSpec(), pod.getMetadata())); } /** Returns services that should be created when environment starts. */ @@ -146,6 +203,8 @@ public class KubernetesEnvironment extends InternalEnvironment { protected final InternalEnvironment internalEnvironment; protected final Map pods = new HashMap<>(); + protected final Map deployments = new HashMap<>(); + protected final Map podData = new HashMap<>(); protected final Map services = new HashMap<>(); protected final Map ingresses = new HashMap<>(); protected final Map pvcs = new HashMap<>(); @@ -183,6 +242,25 @@ public class KubernetesEnvironment extends InternalEnvironment { public Builder setPods(Map pods) { this.pods.putAll(pods); + pods.entrySet() + .forEach( + e -> { + Pod pod = e.getValue(); + podData.put(e.getKey(), new PodData(pod.getSpec(), pod.getMetadata())); + }); + return this; + } + + public Builder setDeployments(Map deployments) { + this.deployments.putAll(deployments); + deployments + .entrySet() + .forEach( + e -> { + PodTemplateSpec podTemplate = e.getValue().getSpec().getTemplate(); + podData.put( + e.getKey(), new PodData(podTemplate.getSpec(), podTemplate.getMetadata())); + }); return this; } @@ -218,7 +296,49 @@ public class KubernetesEnvironment extends InternalEnvironment { public KubernetesEnvironment build() { return new KubernetesEnvironment( - internalEnvironment, pods, services, ingresses, pvcs, secrets, configMaps); + internalEnvironment, + pods, + deployments, + podData, + services, + ingresses, + pvcs, + secrets, + configMaps); + } + } + + /** + * Abstraction of pod, since deployments store pod spec and meta within a PodSpecTemplate instead + * of a pod object. This class allows us to use one class to support passing of the relevant parts + * of a pod or deployment when it comes to provisioning. + * + *

The methods for accessing metadata and spec are identical to that of the Pod class (i.e. + * {@code getSpec()} and {@code getMetadata()} + */ + public static class PodData { + private PodSpec podSpec; + private ObjectMeta podMeta; + + public PodData(PodSpec podSpec, ObjectMeta podMeta) { + this.podSpec = podSpec; + this.podMeta = podMeta; + } + + public PodSpec getSpec() { + return podSpec; + } + + public void setSpec(PodSpec podSpec) { + this.podSpec = podSpec; + } + + public ObjectMeta getMetadata() { + return podMeta; + } + + public void setMetadata(ObjectMeta podMeta) { + this.podMeta = podMeta; } } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java index f99e2fb60d..a2baa561e2 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactory.java @@ -22,6 +22,7 @@ import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Service; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.extensions.Ingress; import java.io.ByteArrayInputStream; import java.util.ArrayList; @@ -100,6 +101,7 @@ public class KubernetesEnvironmentFactory clientFactory.create().lists().load(new ByteArrayInputStream(content.getBytes())).get(); Map pods = new HashMap<>(); + Map deployments = new HashMap<>(); Map services = new HashMap<>(); boolean isAnyIngressPresent = false; boolean isAnyPVCPresent = false; @@ -109,6 +111,9 @@ public class KubernetesEnvironmentFactory if (object instanceof Pod) { Pod pod = (Pod) object; pods.put(pod.getMetadata().getName(), pod); + } else if (object instanceof Deployment) { + Deployment deployment = (Deployment) object; + deployments.put(deployment.getMetadata().getName(), deployment); } else if (object instanceof Service) { Service service = (Service) object; services.put(service.getMetadata().getName(), service); @@ -158,6 +163,7 @@ public class KubernetesEnvironmentFactory .setMachines(machines) .setWarnings(warnings) .setPods(pods) + .setDeployments(deployments) .setServices(services) .setIngresses(new HashMap<>()) .setPersistentVolumeClaims(new HashMap<>()) diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentValidator.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentValidator.java index 26e00285fc..7196e7059e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentValidator.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentValidator.java @@ -15,11 +15,11 @@ import static java.lang.String.format; import com.google.common.base.Joiner; import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.Pod; import java.util.HashSet; import java.util.Set; import org.eclipse.che.api.core.ValidationException; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Validates {@link KubernetesEnvironment}. @@ -35,10 +35,10 @@ public class KubernetesEnvironmentValidator { * @throws ValidationException if the specified {@link KubernetesEnvironment} is invalid */ public void validate(KubernetesEnvironment env) throws ValidationException { - checkArgument(!env.getPods().isEmpty(), "Environment should contain at least 1 pod"); + checkArgument(!env.getPodData().isEmpty(), "Environment should contain at least 1 pod"); Set missingMachines = new HashSet<>(env.getMachines().keySet()); - for (Pod pod : env.getPods().values()) { + for (PodData pod : env.getPodData().values()) { if (pod.getSpec() != null && pod.getSpec().getContainers() != null) { for (Container container : pod.getSpec().getContainers()) { missingMachines.remove(Names.machineName(pod, container)); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesDeployments.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesDeployments.java index 7af06c880b..cc267ba883 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesDeployments.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesDeployments.java @@ -29,6 +29,7 @@ import io.fabric8.kubernetes.api.model.OwnerReference; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.api.model.apps.DoneableDeployment; import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.Watch; @@ -125,38 +126,59 @@ public class KubernetesDeployments { putLabel(pod, CHE_WORKSPACE_ID_LABEL, workspaceId); ObjectMeta metadata = pod.getMetadata(); - // Note: metadata.name will be changed as for pods it is set by the deployment. - String originalName = metadata.getName(); - putLabel(pod, CHE_DEPLOYMENT_NAME_LABEL, originalName); - PodSpec podSpec = pod.getSpec(); podSpec.setRestartPolicy("Always"); // Only allowable value + + Deployment deployment = + new DeploymentBuilder() + .withMetadata(metadata) + .withNewSpec() + .withNewSelector() + .withMatchLabels(metadata.getLabels()) + .endSelector() + .withReplicas(1) + .withNewTemplate() + .withMetadata(metadata) + .withSpec(podSpec) + .endTemplate() + .endSpec() + .build(); + return createDeployment(deployment, workspaceId); + } + + public Pod deploy(Deployment deployment) throws InfrastructureException { + ObjectMeta podMeta = deployment.getSpec().getTemplate().getMetadata(); + putLabel(podMeta, CHE_WORKSPACE_ID_LABEL, workspaceId); + putLabel(podMeta, CHE_DEPLOYMENT_NAME_LABEL, deployment.getMetadata().getName()); + putLabel(deployment.getMetadata(), CHE_WORKSPACE_ID_LABEL, workspaceId); + // Match condition for a deployment is an AND of all labels + deployment.getSpec().getSelector().setMatchLabels(podMeta.getLabels()); + // Avoid accidental setting of multiple replicas + deployment.getSpec().setReplicas(1); + + PodSpec podSpec = deployment.getSpec().getTemplate().getSpec(); + podSpec.setRestartPolicy("Always"); // Only allowable value + + return createDeployment(deployment, workspaceId); + } + + private Pod createDeployment(Deployment deployment, String workspaceId) + throws InfrastructureException { + final String deploymentName = deployment.getMetadata().getName(); final CompletableFuture createFuture = new CompletableFuture<>(); final Watch createWatch = clientFactory .create(workspaceId) .pods() .inNamespace(namespace) - .watch(new CreateWatcher(createFuture, workspaceId, originalName)); + .watch(new CreateWatcher(createFuture, workspaceId, deploymentName)); try { clientFactory .create(workspaceId) .apps() .deployments() .inNamespace(namespace) - .createNew() - .withMetadata(metadata) - .withNewSpec() - .withNewSelector() - .withMatchLabels(metadata.getLabels()) - .endSelector() - .withReplicas(1) - .withNewTemplate() - .withMetadata(metadata) - .withSpec(podSpec) - .endTemplate() - .endSpec() - .done(); + .create(deployment); return createFuture.get(POD_CREATION_TIMEOUT_MIN, TimeUnit.MINUTES); } catch (KubernetesClientException e) { throw new KubernetesInfrastructureException(e); @@ -165,17 +187,17 @@ public class KubernetesDeployments { throw new InfrastructureException( String.format( "Interrupted while waiting for Pod creation. -id: %s -message: %s", - metadata.getName(), e.getMessage())); + deploymentName, e.getMessage())); } catch (ExecutionException e) { throw new InfrastructureException( String.format( "Error occured while waiting for Pod creation. -id: %s -message: %s", - metadata.getName(), e.getCause().getMessage())); + deploymentName, e.getCause().getMessage())); } catch (TimeoutException e) { throw new InfrastructureException( String.format( "Pod creation timeout exceeded. -id: %s -message: %s", - metadata.getName(), e.getMessage())); + deploymentName, e.getMessage())); } finally { createWatch.close(); } @@ -894,19 +916,20 @@ public class KubernetesDeployments { private final CompletableFuture future; private final String workspaceId; - private final String originalName; + private final String deploymentName; - private CreateWatcher(CompletableFuture future, String workspaceId, String originalName) { + private CreateWatcher( + CompletableFuture future, String workspaceId, String deploymentName) { this.future = future; this.workspaceId = workspaceId; - this.originalName = originalName; + this.deploymentName = deploymentName; } @Override public void eventReceived(Action action, Pod resource) { Map labels = resource.getMetadata().getLabels(); if (workspaceId.equals(labels.get(CHE_WORKSPACE_ID_LABEL)) - && originalName.equals(labels.get(CHE_DEPLOYMENT_NAME_LABEL))) { + && deploymentName.equals(labels.get(CHE_DEPLOYMENT_NAME_LABEL))) { future.complete(resource); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java index 48e77460d4..cce24ced71 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/KubernetesObjectUtil.java @@ -27,6 +27,7 @@ import io.fabric8.kubernetes.api.model.VolumeMount; import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import java.util.HashMap; import java.util.Map; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Helps to work with Kubernetes objects. @@ -45,6 +46,20 @@ public class KubernetesObjectUtil { target.setMetadata(metadata = new ObjectMeta()); } + putLabel(target.getMetadata(), key, value); + } + + public static void putLabel(PodData target, String key, String value) { + ObjectMeta metadata = target.getMetadata(); + + if (metadata == null) { + target.setMetadata(metadata = new ObjectMeta()); + } + + putLabel(metadata, key, value); + } + + public static void putLabel(ObjectMeta metadata, String key, String value) { Map labels = metadata.getLabels(); if (labels == null) { metadata.setLabels(labels = new HashMap<>()); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java index 14bbf38539..b1f878b7d1 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/CommonPVCStrategy.java @@ -21,7 +21,6 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.Logs import com.google.inject.Inject; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSpec; import java.util.ArrayList; import java.util.Collection; @@ -40,6 +39,7 @@ import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; 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.KubernetesPersistentVolumeClaims; @@ -128,7 +128,7 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy { String commonPVCName = getCommonPVCName(identity); final PersistentVolumeClaim pvc = newPVC(commonPVCName, pvcAccessMode, pvcQuantity); k8sEnv.getPersistentVolumeClaims().put(commonPVCName, pvc); - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { PodSpec podSpec = pod.getSpec(); List containers = new ArrayList<>(); containers.addAll(podSpec.getContainers()); @@ -198,7 +198,7 @@ public class CommonPVCStrategy implements WorkspaceVolumesStrategy { String pvcName, String workspaceId, Set subPaths, - Pod pod, + PodData pod, Container container, Map volumes) { if (volumes.isEmpty()) { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java index cf22758a96..bc04c3d89f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/EphemeralWorkspaceAdapter.java @@ -15,7 +15,6 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.Kube import static org.eclipse.che.workspace.infrastructure.kubernetes.provision.LogsVolumeMachineProvisioner.LOGS_VOLUME_NAME; import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.VolumeBuilder; import java.util.ArrayList; @@ -29,6 +28,7 @@ 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.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,7 +51,7 @@ public class EphemeralWorkspaceAdapter { public void provision(KubernetesEnvironment k8sEnv, RuntimeIdentity identity) throws InfrastructureException { LOG.debug("Provisioning PVC strategy for workspace '{}'", identity.getWorkspaceId()); - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { PodSpec podSpec = pod.getSpec(); // To ensure same volumes get mounted correctly in different containers, we need to track diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java index 9aaef06ac6..670642e9d7 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/PVCSubPathHelper.java @@ -136,7 +136,7 @@ public class PVCSubPathHelper { final String podName = jobName + '-' + workspaceId; final String[] command = buildCommand(commandBase, arguments); final Pod pod = newPod(podName, command); - securityContextProvisioner.provision(pod); + securityContextProvisioner.provision(pod.getSpec()); KubernetesDeployments deployments = null; try { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java index d308dc1a81..e4b260e899 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/namespace/pvc/UniqueWorkspacePVCStrategy.java @@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableMap; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSpec; import java.util.ArrayList; import java.util.Collection; @@ -41,6 +40,7 @@ import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesNamespaceFactory; import org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesPersistentVolumeClaims; import org.slf4j.Logger; @@ -115,7 +115,7 @@ public class UniqueWorkspacePVCStrategy implements WorkspaceVolumesStrategy { .create(workspaceId) .persistentVolumeClaims() .getByLabel(CHE_WORKSPACE_ID_LABEL, workspaceId)); - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { final PodSpec podSpec = pod.getSpec(); List containers = new ArrayList<>(); containers.addAll(podSpec.getContainers()); @@ -158,7 +158,7 @@ public class UniqueWorkspacePVCStrategy implements WorkspaceVolumesStrategy { String workspaceId, Map provisionedClaims, Map existingVolumeName2PVC, - Pod pod, + PodData pod, Container container, Map volumes) throws InfrastructureException { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/CertificateProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/CertificateProvisioner.java index 986b7ca576..4e4323f1dd 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/CertificateProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/CertificateProvisioner.java @@ -17,7 +17,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableMap; import com.google.inject.Inject; import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.SecretBuilder; import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Volume; @@ -30,6 +29,7 @@ import javax.inject.Singleton; 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.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Mount configured self-signed certificate as file in each workspace machines if configured. @@ -81,7 +81,7 @@ public class CertificateProvisioner implements ConfigurationProvisioner certVolume = pod.getSpec() .getVolumes() diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ImagePullSecretProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ImagePullSecretProvisioner.java index d2cb279b52..d3e7f48bf4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ImagePullSecretProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ImagePullSecretProvisioner.java @@ -16,7 +16,7 @@ import com.google.gson.Gson; import com.google.gson.stream.JsonWriter; import io.fabric8.kubernetes.api.model.LocalObjectReference; import io.fabric8.kubernetes.api.model.LocalObjectReferenceBuilder; -import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; import java.io.IOException; @@ -93,7 +93,10 @@ public class ImagePullSecretProvisioner implements ConfigurationProvisioner addImagePullSecret(secret.getMetadata().getName(), p)); + k8sEnv + .getPodData() + .values() + .forEach(p -> addImagePullSecret(secret.getMetadata().getName(), p.getSpec())); } /** @@ -160,13 +163,12 @@ public class ImagePullSecretProvisioner implements ConfigurationProvisioner imagePullSecrets = pod.getSpec().getImagePullSecrets(); - pod.getSpec() - .setImagePullSecrets( - ImmutableList.builder() - .add(new LocalObjectReferenceBuilder().withName(secretName).build()) - .addAll(imagePullSecrets) - .build()); + private void addImagePullSecret(String secretName, PodSpec podSpec) { + List imagePullSecrets = podSpec.getImagePullSecrets(); + podSpec.setImagePullSecrets( + ImmutableList.builder() + .add(new LocalObjectReferenceBuilder().withName(secretName).build()) + .addAll(imagePullSecrets) + .build()); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/InstallerServersPortProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/InstallerServersPortProvisioner.java index 05ea22ac4a..03c8fad1c6 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/InstallerServersPortProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/InstallerServersPortProvisioner.java @@ -16,7 +16,6 @@ import static java.util.stream.Collectors.toList; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import io.fabric8.kubernetes.api.model.Pod; import java.util.Collection; import java.util.HashSet; import java.util.List; @@ -37,6 +36,7 @@ import org.eclipse.che.commons.lang.Pair; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Fixes installers servers ports if conflicts are present. @@ -76,7 +76,7 @@ public class InstallerServersPortProvisioner implements ConfigurationProvisioner TracingTags.WORKSPACE_ID.set(identity::getWorkspaceId); - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { // it is needed to detect conflicts between all containers in a pod // because they use the same ports List podMachines = diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/PodTerminationGracePeriodProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/PodTerminationGracePeriodProvisioner.java index 33cab64fca..e879bf083f 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/PodTerminationGracePeriodProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/PodTerminationGracePeriodProvisioner.java @@ -11,7 +11,7 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; -import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodSpec; import javax.inject.Inject; import javax.inject.Named; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; @@ -19,6 +19,7 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Adds grace termination period to workspace pods. @@ -45,8 +46,8 @@ public class PodTerminationGracePeriodProvisioner implements ConfigurationProvis TracingTags.WORKSPACE_ID.set(identity::getWorkspaceId); - for (Pod pod : k8sEnv.getPods().values()) { - if (!isTerminationGracePeriodSet(pod)) { + for (PodData pod : k8sEnv.getPodData().values()) { + if (!isTerminationGracePeriodSet(pod.getSpec())) { pod.getSpec().setTerminationGracePeriodSeconds(graceTerminationPeriodSec); } } @@ -57,7 +58,7 @@ public class PodTerminationGracePeriodProvisioner implements ConfigurationProvis * @return true if 'terminationGracePeriodSeconds' have been explicitly set in Kubernetes / * OpenShift recipe, false otherwise */ - private boolean isTerminationGracePeriodSet(final Pod pod) { - return pod.getSpec().getTerminationGracePeriodSeconds() != null; + private boolean isTerminationGracePeriodSet(final PodSpec podSpec) { + return podSpec.getTerminationGracePeriodSeconds() != null; } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ProxySettingsProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ProxySettingsProvisioner.java index 62ca842c17..cbafa75029 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ProxySettingsProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ProxySettingsProvisioner.java @@ -12,7 +12,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.Pod; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; @@ -22,6 +21,7 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Add proxy configuration to pod containers @@ -60,7 +60,7 @@ public class ProxySettingsProvisioner implements ConfigurationProvisioner { TracingTags.WORKSPACE_ID.set(identity::getWorkspaceId); if (!proxyEnvVars.isEmpty()) { - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { pod.getSpec() .getContainers() .forEach( diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/SecurityContextProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/SecurityContextProvisioner.java index 340f3adffd..895f7030c4 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/SecurityContextProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/SecurityContextProvisioner.java @@ -11,8 +11,8 @@ */ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSecurityContextBuilder; +import io.fabric8.kubernetes.api.model.PodSpec; import javax.inject.Inject; import javax.inject.Named; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; @@ -38,13 +38,12 @@ public class SecurityContextProvisioner implements ConfigurationProvisioner provision(p.getSpec())); } } - public void provision(Pod pod) { - pod.getSpec() - .setSecurityContext( - new PodSecurityContextBuilder().withRunAsUser(runAsUser).withFsGroup(fsGroup).build()); + public void provision(PodSpec podSpec) { + podSpec.setSecurityContext( + new PodSecurityContextBuilder().withRunAsUser(runAsUser).withFsGroup(fsGroup).build()); } } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ServiceAccountProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ServiceAccountProvisioner.java index 347cf71559..f3d97a6c9e 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ServiceAccountProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/ServiceAccountProvisioner.java @@ -13,7 +13,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import static com.google.common.base.Strings.isNullOrEmpty; -import io.fabric8.kubernetes.api.model.Pod; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; @@ -23,6 +22,7 @@ import org.eclipse.che.commons.annotation.Nullable; import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Sets the service account to workspace pods if configured. @@ -51,7 +51,7 @@ public class ServiceAccountProvisioner implements ConfigurationProvisioner { TracingTags.WORKSPACE_ID.set(identity::getWorkspaceId); if (!isNullOrEmpty(serviceAccount)) { - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { pod.getSpec().setServiceAccountName(serviceAccount); pod.getSpec().setAutomountServiceAccountToken(true); } diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/UniqueNamesProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/UniqueNamesProvisioner.java index 41a964cc79..11cde3607c 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/UniqueNamesProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/UniqueNamesProvisioner.java @@ -14,8 +14,8 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision; import static org.eclipse.che.workspace.infrastructure.kubernetes.namespace.KubernetesObjectUtil.putLabel; import io.fabric8.kubernetes.api.model.ObjectMeta; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.extensions.Ingress; +import java.util.Collection; import java.util.HashSet; import java.util.Set; import javax.inject.Singleton; @@ -26,6 +26,7 @@ import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.Constants; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Makes names of Kubernetes pods and ingresses unique whole namespace by {@link Names}. @@ -48,15 +49,14 @@ public class UniqueNamesProvisioner TracingTags.WORKSPACE_ID.set(workspaceId); - final Set pods = new HashSet<>(k8sEnv.getPods().values()); - k8sEnv.getPods().clear(); - for (Pod pod : pods) { + final Collection podData = k8sEnv.getPodData().values(); + for (PodData pod : podData) { final ObjectMeta podMeta = pod.getMetadata(); - putLabel(pod, Constants.CHE_ORIGINAL_NAME_LABEL, podMeta.getName()); + putLabel(podMeta, Constants.CHE_ORIGINAL_NAME_LABEL, podMeta.getName()); final String podName = Names.uniquePodName(podMeta.getName(), workspaceId); podMeta.setName(podName); - k8sEnv.getPods().put(podName, pod); } + final Set ingresses = new HashSet<>(k8sEnv.getIngresses().values()); k8sEnv.getIngresses().clear(); for (Ingress ingress : ingresses) { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/env/EnvVarsConverter.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/env/EnvVarsConverter.java index 6db1cebd2a..991415a354 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/env/EnvVarsConverter.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/env/EnvVarsConverter.java @@ -13,7 +13,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision.env; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.EnvVar; -import io.fabric8.kubernetes.api.model.Pod; import javax.inject.Singleton; import org.eclipse.che.api.core.model.workspace.config.MachineConfig; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; @@ -23,6 +22,7 @@ import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ConfigurationProvisioner; /** @@ -39,7 +39,7 @@ public class EnvVarsConverter implements ConfigurationProvisioner { TracingTags.WORKSPACE_ID.set(identity::getWorkspaceId); - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { for (Container container : pod.getSpec().getContainers()) { String machineName = Names.machineName(pod, container); InternalMachineConfig machineConf = k8sEnv.getMachines().get(machineName); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/limits/ram/RamLimitRequestProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/limits/ram/RamLimitRequestProvisioner.java index eaa30654f7..a11697f032 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/limits/ram/RamLimitRequestProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/limits/ram/RamLimitRequestProvisioner.java @@ -16,7 +16,6 @@ import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMO import static org.eclipse.che.workspace.infrastructure.kubernetes.Names.machineName; import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.Pod; import java.util.Map; import javax.inject.Inject; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; @@ -26,6 +25,7 @@ import org.eclipse.che.api.workspace.server.spi.environment.MemoryAttributeProvi import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ConfigurationProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.util.Containers; @@ -52,7 +52,7 @@ public class RamLimitRequestProvisioner implements ConfigurationProvisioner { TracingTags.WORKSPACE_ID.set(identity::getWorkspaceId); final Map machines = k8sEnv.getMachines(); - for (Pod pod : k8sEnv.getPods().values()) { + for (PodData pod : k8sEnv.getPodData().values()) { for (Container container : pod.getSpec().getContainers()) { InternalMachineConfig machineConfig = machines.get(machineName(pod, container)); memoryAttributeProvisioner.provision( diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/restartpolicy/RestartPolicyRewriter.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/restartpolicy/RestartPolicyRewriter.java index 1ec7be843b..8ba5dcea41 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/restartpolicy/RestartPolicyRewriter.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/restartpolicy/RestartPolicyRewriter.java @@ -13,7 +13,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision.restartpol import static java.lang.String.format; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSpec; import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity; import org.eclipse.che.api.workspace.server.model.impl.WarningImpl; @@ -22,6 +21,7 @@ import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.Warnings; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ConfigurationProvisioner; /** @@ -40,7 +40,7 @@ public class RestartPolicyRewriter implements ConfigurationProvisioner { TracingTags.WORKSPACE_ID.set(identity::getWorkspaceId); - for (Pod podConfig : k8sEnv.getPods().values()) { + for (PodData podConfig : k8sEnv.getPodData().values()) { final String podName = podConfig.getMetadata().getName(); final PodSpec podSpec = podConfig.getSpec(); rewriteRestartPolicy(podSpec, podName, k8sEnv); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/server/ServersConverter.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/server/ServersConverter.java index 245b513cb1..20aad0cede 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/server/ServersConverter.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/provision/server/ServersConverter.java @@ -12,7 +12,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.provision.server; import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSpec; import java.util.Map; import javax.inject.Inject; @@ -25,6 +24,7 @@ import org.eclipse.che.commons.annotation.Traced; import org.eclipse.che.commons.tracing.TracingTags; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ConfigurationProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.server.KubernetesServerExposer; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposerStrategy; @@ -64,7 +64,7 @@ public class ServersConverter SecureServerExposer secureServerExposer = secureServerExposerFactoryProvider.get(k8sEnv).create(identity); - for (Pod podConfig : k8sEnv.getPods().values()) { + for (PodData podConfig : k8sEnv.getPodData().values()) { final PodSpec podSpec = podConfig.getSpec(); for (Container containerConfig : podSpec.getContainers()) { String machineName = Names.machineName(podConfig, containerConfig); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java index 7b0272e733..3fdd06203d 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/KubernetesServerExposer.java @@ -20,7 +20,6 @@ import static org.eclipse.che.workspace.infrastructure.kubernetes.Constants.CHE_ import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.ContainerPort; import io.fabric8.kubernetes.api.model.ContainerPortBuilder; -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.api.model.ServicePortBuilder; @@ -38,6 +37,7 @@ import org.eclipse.che.api.workspace.server.spi.InfrastructureException; import org.eclipse.che.workspace.infrastructure.kubernetes.Annotations; import org.eclipse.che.workspace.infrastructure.kubernetes.Constants; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.provision.UniqueNamesProvisioner; import org.eclipse.che.workspace.infrastructure.kubernetes.server.external.ExternalServerExposerStrategy; import org.eclipse.che.workspace.infrastructure.kubernetes.server.secure.SecureServerExposer; @@ -107,14 +107,14 @@ public class KubernetesServerExposer { private final SecureServerExposer secureServerExposer; private final String machineName; private final Container container; - private final Pod pod; + private final PodData pod; private final T k8sEnv; public KubernetesServerExposer( ExternalServerExposerStrategy externalServerExposer, SecureServerExposer secureServerExposer, String machineName, - Pod pod, + PodData pod, Container container, T k8sEnv) { this.externalServerExposer = externalServerExposer; diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java index c7e208d28a..fa44478c44 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/server/secure/jwtproxy/JwtProxyProvisioner.java @@ -213,7 +213,7 @@ public class JwtProxyProvisioner { private void ensureJwtProxyInjected(KubernetesEnvironment k8sEnv) throws InfrastructureException { if (!k8sEnv.getMachines().containsKey(JWT_PROXY_MACHINE_NAME)) { k8sEnv.getMachines().put(JWT_PROXY_MACHINE_NAME, createJwtProxyMachine()); - k8sEnv.getPods().put(JWT_PROXY_POD_NAME, createJwtProxyPod()); + k8sEnv.addPod(JWT_PROXY_POD_NAME, createJwtProxyPod()); KeyPair keyPair; try { diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesBrokerInitContainerApplier.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesBrokerInitContainerApplier.java index e3c21bafe4..620b1cc8a1 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesBrokerInitContainerApplier.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesBrokerInitContainerApplier.java @@ -14,7 +14,6 @@ package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins; import com.google.common.annotations.Beta; import com.google.inject.Inject; import io.fabric8.kubernetes.api.model.Container; -import io.fabric8.kubernetes.api.model.Pod; import java.util.Collection; import java.util.List; import java.util.Map; @@ -25,6 +24,7 @@ import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfi import org.eclipse.che.api.workspace.server.wsplugins.model.PluginMeta; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory; /** @@ -58,18 +58,18 @@ public class KubernetesBrokerInitContainerApplier workspacePods = workspaceEnvironment.getPods(); + Map workspacePods = workspaceEnvironment.getPodData(); if (workspacePods.size() != 1) { throw new InfrastructureException( "Che plugins tooling configuration can be applied to a workspace with one pod only."); } - Pod workspacePod = workspacePods.values().iterator().next(); + PodData workspacePod = workspacePods.values().iterator().next(); - Map brokerPods = brokerEnvironment.getPods(); + Map brokerPods = brokerEnvironment.getPodData(); if (brokerPods.size() != 1) { throw new InfrastructureException("Broker environment must have only one Pod."); } - Pod brokerPod = brokerPods.values().iterator().next(); + PodData brokerPod = brokerPods.values().iterator().next(); // Add broker machines to workspace environment so that the init containers can be provisioned. List brokerContainers = brokerPod.getSpec().getContainers(); diff --git a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java index 154d72d875..8f75598440 100644 --- a/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java +++ b/infrastructures/kubernetes/src/main/java/org/eclipse/che/workspace/infrastructure/kubernetes/wsplugins/KubernetesPluginsToolingApplier.java @@ -45,6 +45,7 @@ import org.eclipse.che.api.workspace.server.wsplugins.model.Command; import org.eclipse.che.workspace.infrastructure.kubernetes.Names; import org.eclipse.che.workspace.infrastructure.kubernetes.Warnings; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Applies Che plugins tooling configuration to a kubernetes internal runtime object. @@ -84,10 +85,11 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { KubernetesEnvironment kubernetesEnvironment = (KubernetesEnvironment) internalEnvironment; - Map pods = kubernetesEnvironment.getPods(); + Map pods = kubernetesEnvironment.getPodData(); switch (pods.size()) { case 0: addToolingPod(kubernetesEnvironment); + pods = kubernetesEnvironment.getPodData(); break; case 1: break; @@ -95,7 +97,7 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { throw new InfrastructureException( "Che plugins tooling configuration can be applied to a workspace with one pod only"); } - Pod pod = pods.values().iterator().next(); + PodData pod = pods.values().iterator().next(); CommandsResolver commandsResolver = new CommandsResolver(kubernetesEnvironment); for (ChePlugin chePlugin : chePlugins) { @@ -125,7 +127,7 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { .endSpec() .build(); - kubernetesEnvironment.getPods().put(CHE_WORKSPACE_POD, pod); + kubernetesEnvironment.addPod(CHE_WORKSPACE_POD, pod); } private void populateWorkspaceEnvVars( @@ -133,7 +135,7 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { List workspaceEnv = toK8sEnvVars(chePlugin.getWorkspaceEnv()); kubernetesEnvironment - .getPods() + .getPodData() .values() .stream() .flatMap(pod -> pod.getSpec().getContainers().stream()) @@ -161,7 +163,7 @@ public class KubernetesPluginsToolingApplier implements ChePluginsApplier { * @throws InfrastructureException when any error occurs */ private void addSidecar( - Pod pod, + PodData pod, CheContainer container, ChePlugin chePlugin, KubernetesEnvironment kubernetesEnvironment, 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 a64d2d65a1..7d3673f5b5 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 @@ -75,7 +75,7 @@ public class DeployBroker extends BrokerPhase { namespace.configMaps().create(configMap); } - Pod pluginBrokerPod = getPluginBrokerPod(brokerEnvironment.getPods()); + Pod pluginBrokerPod = getPluginBrokerPod(brokerEnvironment.getPodsCopy()); if (factory.isConfigured()) { UnrecoverablePodEventListener unrecoverableEventListener = diff --git a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactoryTest.java b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactoryTest.java index 1d23afc342..1b021fc6e0 100644 --- a/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactoryTest.java +++ b/infrastructures/kubernetes/src/test/java/org/eclipse/che/workspace/infrastructure/kubernetes/environment/KubernetesEnvironmentFactoryTest.java @@ -45,10 +45,15 @@ import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder; import io.fabric8.kubernetes.api.model.Quantity; import io.fabric8.kubernetes.api.model.ResourceRequirements; import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.api.model.extensions.Ingress; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.KubernetesListMixedOperation; @@ -176,6 +181,116 @@ public class KubernetesEnvironmentFactoryTest { new WarningImpl(CONFIG_MAP_IGNORED_WARNING_CODE, CONFIG_MAP_IGNORED_WARNING_MESSAGE)); } + @Test + public void addPodsWhenRecipeContainsThem() throws Exception { + Pod pod = + new PodBuilder() + .withNewMetadata() + .withName("pod-test") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + + final List recipeObjects = singletonList(pod); + when(validatedObjects.getItems()).thenReturn(recipeObjects); + + final KubernetesEnvironment parsed = + k8sEnvironmentFactory.doCreate(internalRecipe, emptyMap(), emptyList()); + + assertEquals(parsed.getPodsCopy().size(), 1); + assertEquals( + parsed.getPodsCopy().values().iterator().next().getMetadata().getName(), + pod.getMetadata().getName()); + assertEquals(parsed.getPodData().size(), 1); + assertEquals( + parsed.getPodData().values().iterator().next().getMetadata().getName(), + pod.getMetadata().getName()); + } + + @Test + public void addDeploymentsWhenRecipeContainsThem() throws Exception { + PodTemplateSpec podTemplate = + new PodTemplateSpecBuilder() + .withNewMetadata() + .withName("deployment-pod") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + Deployment deployment = + new DeploymentBuilder() + .withNewMetadata() + .withName("deployment-test") + .endMetadata() + .withNewSpec() + .withTemplate(podTemplate) + .endSpec() + .build(); + + final List recipeObjects = singletonList(deployment); + when(validatedObjects.getItems()).thenReturn(recipeObjects); + + final KubernetesEnvironment parsed = + k8sEnvironmentFactory.doCreate(internalRecipe, emptyMap(), emptyList()); + + assertEquals(parsed.getDeploymentsCopy().size(), 1); + assertEquals( + parsed.getDeploymentsCopy().values().iterator().next().getMetadata().getName(), + deployment.getMetadata().getName()); + assertEquals(parsed.getPodData().size(), 1); + assertEquals( + parsed.getPodData().values().iterator().next().getMetadata().getName(), + podTemplate.getMetadata().getName()); + } + + @Test + public void bothPodsAndDeploymentsIncludedInPodData() throws Exception { + PodTemplateSpec podTemplate = + new PodTemplateSpecBuilder() + .withNewMetadata() + .withName("deployment-pod") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + Deployment deployment = + new DeploymentBuilder() + .withNewMetadata() + .withName("deployment-test") + .endMetadata() + .withNewSpec() + .withTemplate(podTemplate) + .endSpec() + .build(); + Pod pod = + new PodBuilder() + .withNewMetadata() + .withName("bare-pod") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + final List recipeObjects = asList(deployment, pod); + when(validatedObjects.getItems()).thenReturn(recipeObjects); + + final KubernetesEnvironment parsed = + k8sEnvironmentFactory.doCreate(internalRecipe, emptyMap(), emptyList()); + + assertEquals(parsed.getPodData().size(), 2); + assertTrue( + parsed + .getPodData() + .values() + .stream() + .allMatch( + podData -> { + String name = podData.getMetadata().getName(); + return name.equals(podTemplate.getMetadata().getName()) + || name.equals(pod.getMetadata().getName()); + })); + } + @Test public void testProvisionRamAttributesIsInvoked() throws Exception { final long firstMachineRamLimit = 3072; diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java index 4d3d961bc6..a561868ea8 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/OpenShiftInternalRuntime.java @@ -13,14 +13,13 @@ package org.eclipse.che.workspace.infrastructure.openshift; import com.google.inject.assistedinject.Assisted; import io.fabric8.kubernetes.api.model.ConfigMap; -import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.openshift.api.model.Route; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import javax.inject.Inject; import javax.inject.Named; @@ -123,10 +122,12 @@ public class OpenShiftInternalRuntime extends KubernetesInternalRuntime pods = getContext().getEnvironment().getPods(); + Set toWatch = new HashSet<>(); + OpenShiftEnvironment environment = getContext().getEnvironment(); + toWatch.addAll(environment.getPodsCopy().keySet()); + toWatch.addAll(environment.getDeploymentsCopy().keySet()); UnrecoverablePodEventListener handler = - unrecoverablePodEventListenerFactory.create( - pods.keySet(), this::handleUnrecoverableEvent); + unrecoverablePodEventListenerFactory.create(toWatch, this::handleUnrecoverableEvent); project.deployments().watchEvents(handler); } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java index b297ae1d61..db16653c10 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironment.java @@ -14,8 +14,10 @@ package org.eclipse.che.workspace.infrastructure.openshift.environment; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Service; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.extensions.Ingress; import io.fabric8.openshift.api.model.Route; import java.util.HashMap; @@ -27,6 +29,7 @@ import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfi import org.eclipse.che.api.workspace.server.spi.environment.InternalRecipe; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment; import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.Builder; +import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment.PodData; /** * Holds objects of OpenShift environment. @@ -63,13 +66,24 @@ public class OpenShiftEnvironment extends KubernetesEnvironment { public OpenShiftEnvironment( InternalEnvironment internalEnvironment, Map pods, + Map deployments, + Map podData, Map services, Map ingresses, Map pvcs, Map secrets, Map configMaps, Map routes) { - super(internalEnvironment, pods, services, ingresses, pvcs, secrets, configMaps); + super( + internalEnvironment, + pods, + deployments, + podData, + services, + ingresses, + pvcs, + secrets, + configMaps); setType(TYPE); this.routes = routes; } @@ -79,13 +93,26 @@ public class OpenShiftEnvironment extends KubernetesEnvironment { Map machines, List warnings, Map pods, + Map deployments, + Map podData, Map services, Map ingresses, Map pvcs, Map secrets, Map configMaps, Map routes) { - super(internalRecipe, machines, warnings, pods, services, ingresses, pvcs, secrets, configMaps); + super( + internalRecipe, + machines, + warnings, + pods, + deployments, + podData, + services, + ingresses, + pvcs, + secrets, + configMaps); setType(TYPE); this.routes = routes; } @@ -130,6 +157,26 @@ public class OpenShiftEnvironment extends KubernetesEnvironment { @Override public Builder setPods(Map pods) { this.pods.putAll(pods); + pods.entrySet() + .forEach( + e -> { + Pod pod = e.getValue(); + podData.put(e.getKey(), new PodData(pod.getSpec(), pod.getMetadata())); + }); + return this; + } + + @Override + public Builder setDeployments(Map deployments) { + this.deployments.putAll(deployments); + deployments + .entrySet() + .forEach( + e -> { + PodTemplateSpec podTemplate = e.getValue().getSpec().getTemplate(); + podData.put( + e.getKey(), new PodData(podTemplate.getSpec(), podTemplate.getMetadata())); + }); return this; } @@ -176,7 +223,16 @@ public class OpenShiftEnvironment extends KubernetesEnvironment { public OpenShiftEnvironment build() { return new OpenShiftEnvironment( - internalEnvironment, pods, services, ingresses, pvcs, secrets, configMaps, routes); + internalEnvironment, + pods, + deployments, + podData, + services, + ingresses, + pvcs, + secrets, + configMaps, + routes); } } } diff --git a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java index c728eee88d..238c5a4292 100644 --- a/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java +++ b/infrastructures/openshift/src/main/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactory.java @@ -22,6 +22,7 @@ import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Service; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.openshift.api.model.DeploymentConfig; import io.fabric8.openshift.api.model.Route; import java.io.ByteArrayInputStream; @@ -101,6 +102,7 @@ public class OpenShiftEnvironmentFactory extends InternalEnvironmentFactory pods = new HashMap<>(); + Map deployments = new HashMap<>(); Map services = new HashMap<>(); boolean isAnyRoutePresent = false; boolean isAnyPVCPresent = false; @@ -112,6 +114,9 @@ public class OpenShiftEnvironmentFactory extends InternalEnvironmentFactory()) .setSecrets(new HashMap<>()) diff --git a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactoryTest.java b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactoryTest.java index 7b5b55ae67..9ecefffd65 100644 --- a/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactoryTest.java +++ b/infrastructures/openshift/src/test/java/org/eclipse/che/workspace/infrastructure/openshift/environment/OpenShiftEnvironmentFactoryTest.java @@ -44,10 +44,15 @@ import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.PodBuilder; import io.fabric8.kubernetes.api.model.PodSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpec; +import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder; import io.fabric8.kubernetes.api.model.Quantity; import io.fabric8.kubernetes.api.model.ResourceRequirements; import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.apps.Deployment; +import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.fabric8.kubernetes.client.dsl.KubernetesListMixedOperation; import io.fabric8.kubernetes.client.dsl.RecreateFromServerGettable; import io.fabric8.openshift.api.model.Route; @@ -175,6 +180,116 @@ public class OpenShiftEnvironmentFactoryTest { new WarningImpl(CONFIG_MAP_IGNORED_WARNING_CODE, CONFIG_MAP_IGNORED_WARNING_MESSAGE)); } + @Test + public void addPodsWhenRecipeContainsThem() throws Exception { + Pod pod = + new PodBuilder() + .withNewMetadata() + .withName("pod-test") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + + final List recipeObjects = singletonList(pod); + when(validatedObjects.getItems()).thenReturn(recipeObjects); + + final KubernetesEnvironment parsed = + osEnvironmentFactory.doCreate(internalRecipe, emptyMap(), emptyList()); + + assertEquals(parsed.getPodsCopy().size(), 1); + assertEquals( + parsed.getPodsCopy().values().iterator().next().getMetadata().getName(), + pod.getMetadata().getName()); + assertEquals(parsed.getPodData().size(), 1); + assertEquals( + parsed.getPodData().values().iterator().next().getMetadata().getName(), + pod.getMetadata().getName()); + } + + @Test + public void addDeploymentsWhenRecipeContainsThem() throws Exception { + PodTemplateSpec podTemplate = + new PodTemplateSpecBuilder() + .withNewMetadata() + .withName("deployment-pod") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + Deployment deployment = + new DeploymentBuilder() + .withNewMetadata() + .withName("deployment-test") + .endMetadata() + .withNewSpec() + .withTemplate(podTemplate) + .endSpec() + .build(); + + final List recipeObjects = singletonList(deployment); + when(validatedObjects.getItems()).thenReturn(recipeObjects); + + final KubernetesEnvironment parsed = + osEnvironmentFactory.doCreate(internalRecipe, emptyMap(), emptyList()); + + assertEquals(parsed.getDeploymentsCopy().size(), 1); + assertEquals( + parsed.getDeploymentsCopy().values().iterator().next().getMetadata().getName(), + deployment.getMetadata().getName()); + assertEquals(parsed.getPodData().size(), 1); + assertEquals( + parsed.getPodData().values().iterator().next().getMetadata().getName(), + podTemplate.getMetadata().getName()); + } + + @Test + public void bothPodsAndDeploymentsIncludedInPodData() throws Exception { + PodTemplateSpec podTemplate = + new PodTemplateSpecBuilder() + .withNewMetadata() + .withName("deployment-pod") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + Deployment deployment = + new DeploymentBuilder() + .withNewMetadata() + .withName("deployment-test") + .endMetadata() + .withNewSpec() + .withTemplate(podTemplate) + .endSpec() + .build(); + Pod pod = + new PodBuilder() + .withNewMetadata() + .withName("bare-pod") + .endMetadata() + .withNewSpec() + .endSpec() + .build(); + final List recipeObjects = asList(deployment, pod); + when(validatedObjects.getItems()).thenReturn(recipeObjects); + + final KubernetesEnvironment parsed = + osEnvironmentFactory.doCreate(internalRecipe, emptyMap(), emptyList()); + + assertEquals(parsed.getPodData().size(), 2); + assertTrue( + parsed + .getPodData() + .values() + .stream() + .allMatch( + podData -> { + String name = podData.getMetadata().getName(); + return name.equals(podTemplate.getMetadata().getName()) + || name.equals(pod.getMetadata().getName()); + })); + } + @Test public void testProvisionRamAttributesIsInvoked() throws Exception { final long firstMachineRamLimit = 3072 * BYTES_IN_MB;