<commit_before>/*
 * Copyright (c) 2012-2018 Red Hat, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Red Hat, Inc. - initial API and implementation
 */
package org.eclipse.che.workspace.infrastructure.kubernetes.wsnext;

import static java.util.stream.Collectors.toMap;
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE;

import com.google.common.annotations.Beta;
import io.fabric8.kubernetes.api.model.ContainerBuilder;
import io.fabric8.kubernetes.api.model.Pod;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
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.InternalEnvironment;
import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig;
import org.eclipse.che.api.workspace.server.wsnext.WorkspaceNextApplier;
import org.eclipse.che.api.workspace.server.wsnext.model.CheContainer;
import org.eclipse.che.api.workspace.server.wsnext.model.CheContainerPort;
import org.eclipse.che.api.workspace.server.wsnext.model.ChePlugin;
import org.eclipse.che.api.workspace.server.wsnext.model.ChePluginEndpoint;
import org.eclipse.che.api.workspace.server.wsnext.model.EnvVar;
import org.eclipse.che.api.workspace.server.wsnext.model.Volume;
import org.eclipse.che.workspace.infrastructure.kubernetes.Names;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.util.Containers;

/**
 * Applies Workspace.Next configuration to a kubernetes internal runtime object.
 *
 * @author <NAME>
 */
@Beta
public class KubernetesWorkspaceNextApplier implements WorkspaceNextApplier {

  private final String defaultMachineMemorySizeAttribute;

  @Inject
  public KubernetesWorkspaceNextApplier(
      @Named("che.workspace.default_memory_mb") long defaultMachineMemorySizeMB) {
    this.defaultMachineMemorySizeAttribute =
        String.valueOf(defaultMachineMemorySizeMB * 1024 * 1024);
  }

  @Override
  public void apply(InternalEnvironment internalEnvironment, Collection<ChePlugin> chePlugins)
      throws InfrastructureException {
    if (chePlugins.isEmpty()) {
      return;
    }
    KubernetesEnvironment kubernetesEnvironment = (KubernetesEnvironment) internalEnvironment;
    Map<String, Pod> pods = kubernetesEnvironment.getPods();
    if (pods.size() != 1) {
      throw new InfrastructureException(
          "Workspace.Next configuration can be applied to a workspace with one pod only");
    }
    Pod pod = pods.values().iterator().next();
    for (ChePlugin chePlugin : chePlugins) {
      for (CheContainer container : chePlugin.getContainers()) {
        io.fabric8.kubernetes.api.model.Container k8sContainer =
            addContainer(pod, container.getImage(), container.getEnv());

        String machineName = Names.machineName(pod, k8sContainer);

        InternalMachineConfig machineConfig =
            addMachine(
                kubernetesEnvironment,
                machineName,
                getContainerEndpoints(container.getPorts(), chePlugin.getEndpoints()),
                container.getVolumes());

        normalizeMemory(k8sContainer, machineConfig);
      }
    }
  }

  private io.fabric8.kubernetes.api.model.Container addContainer(
      Pod toolingPod, String image, List<EnvVar> env) {
    io.fabric8.kubernetes.api.model.Container container =
        new ContainerBuilder()
            .withImage(image)
            .withName(Names.generateName("tooling"))
            .withEnv(toK8sEnv(env))
            .build();
    toolingPod.getSpec().getContainers().add(container);
    return container;
  }

  private InternalMachineConfig addMachine(
      KubernetesEnvironment kubernetesEnvironment,
      String machineName,
      List<ChePluginEndpoint> endpoints,
      List<Volume> volumes) {

    InternalMachineConfig machineConfig =
        new InternalMachineConfig(
            null, toWorkspaceServers(endpoints), null, null, toWorkspaceVolumes(volumes));
    kubernetesEnvironment.getMachines().put(machineName, machineConfig);

    return machineConfig;
  }

  private List<ChePluginEndpoint> getContainerEndpoints(
      List<CheContainerPort> ports, List<ChePluginEndpoint> endpoints) {

    if (ports != null) {
      return ports
          .stream()
          .flatMap(
              cheContainerPort -><commit_msg>Refactor k8s impl of WorkspaceNext applier<commit_after>/*
 * Copyright (c) 2012-2018 Red Hat, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Red Hat, Inc. - initial API and implementation
 */
package org.eclipse.che.workspace.infrastructure.kubernetes.wsnext;

import static java.util.stream.Collectors.toMap;
import static org.eclipse.che.api.core.model.workspace.config.MachineConfig.MEMORY_LIMIT_ATTRIBUTE;

import com.google.common.annotations.Beta;
import io.fabric8.kubernetes.api.model.ContainerBuilder;
import io.fabric8.kubernetes.api.model.Pod;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
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.InternalEnvironment;
import org.eclipse.che.api.workspace.server.spi.environment.InternalMachineConfig;
import org.eclipse.che.api.workspace.server.wsnext.WorkspaceNextApplier;
import org.eclipse.che.api.workspace.server.wsnext.model.CheContainer;
import org.eclipse.che.api.workspace.server.wsnext.model.CheContainerPort;
import org.eclipse.che.api.workspace.server.wsnext.model.ChePlugin;
import org.eclipse.che.api.workspace.server.wsnext.model.ChePluginEndpoint;
import org.eclipse.che.api.workspace.server.wsnext.model.EnvVar;
import org.eclipse.che.api.workspace.server.wsnext.model.Volume;
import org.eclipse.che.workspace.infrastructure.kubernetes.Names;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.util.Containers;

/**
 * Applies Workspace.Next configuration to a kubernetes internal runtime object.
 *
 * @author <NAME>
 */
@Beta
public class KubernetesWorkspaceNextApplier implements WorkspaceNextApplier {

  private final String defaultMachineMemorySizeAttribute;

  @Inject
  public KubernetesWorkspaceNextApplier(
      @Named("che.workspace.default_memory_mb") long defaultMachineMemorySizeMB) {
    this.defaultMachineMemorySizeAttribute =
        String.valueOf(defaultMachineMemorySizeMB * 1024 * 1024);
  }

  @Override
  public void apply(InternalEnvironment internalEnvironment, Collection<ChePlugin> chePlugins)
      throws InfrastructureException {
    if (chePlugins.isEmpty()) {
      return;
    }

    KubernetesEnvironment kubernetesEnvironment = (KubernetesEnvironment) internalEnvironment;

    Map<String, Pod> pods = kubernetesEnvironment.getPods();
    if (pods.size() != 1) {
      throw new InfrastructureException(
          "Workspace.Next configuration can be applied to a workspace with one pod only");
    }
    Pod pod = pods.values().iterator().next();

    for (ChePlugin chePlugin : chePlugins) {
      for (CheContainer container : chePlugin.getContainers()) {
        addMachine(pod, container, chePlugin, kubernetesEnvironment);
      }
    }
  }

  private void addMachine(
      Pod pod,
      CheContainer container,
      ChePlugin chePlugin,
      KubernetesEnvironment kubernetesEnvironment) {

    List<ChePluginEndpoint> containerEndpoints =
        getContainerEndpoints(container.getPorts(), chePlugin.getEndpoints());
    io.fabric8.kubernetes.api.model.Container k8sContainer =
        addContainer(pod, container.getImage(), container.getEnv());

    String machineName = Names.machineName(pod, k8sContainer);

    InternalMachineConfig machineConfig =
        addMachineConfig(
            kubernetesEnvironment, machineName, containerEndpoints, container.getVolumes());

    normalizeMemory(k8sContainer, machineConfig);
  }

  private io.fabric8.kubernetes.api.model.Container addContainer(
      Pod toolingPod, String image, List<EnvVar> env) {
    io.fabric8.kubernetes.api.model.Container container =
        new ContainerBuilder()
            .withImage(image)
            .withName(Names.generateName("tooling"))
            .withEnv(toK8sEnv(env))
            .build();
    toolingPod.getSpec().getContainers().add(container);
    return container;
  }

  private InternalMachineConfig addMachineConfig(
      KubernetesEnvironment kubernetesEnvironment,
      String machineName,
      List<ChePluginEndpoint> endpoints,
      List<Volume> volumes) {

    InternalMachineConfig machineConfig =
        new InternalMachineConfig(
            null, toWorkspaceServers(endpoints), null, null, toWorkspaceVolumes(volumes));
    kubernetesEnvironment.getMachines().put(machineName, machineConfig);

    return machineConfig;
  }

  private List<ChePluginEndpoint> getContainerEndpoints(
      List<CheContainerPort> ports, List<ChePluginEndpoint> endpoints) {

    if (ports != null) {
      return ports
          .stream()
          .flatMap(
              cheContainerPort ->
{'fraction_non_alphanumeric': 0.09710326243864884, 'fraction_numerical': 0.0058704648253296125, 'mean_word_length': 4.165009940357853, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4270312', 'n_tokens_mistral': 2927, 'n_tokens_neox': 2827, 'n_words': 557}