Skip to content

Commit

Permalink
Refactor plugin brokering process
Browse files Browse the repository at this point in the history
Refactor the plugin brokering process to accomodate changes in plugin
brokers (splitting brokers into a metadata and artifacts broker)

Co-authored-by: Sergii Leshchenko <sleshche@redhat.com>

Signed-off-by: Angel Misevski <amisevsk@redhat.com>
  • Loading branch information
amisevsk committed Jan 9, 2020
1 parent 83f9101 commit 8c27ba9
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,8 @@ che.singleport.wildcard_domain.ipless=false

# Docker image of Che plugin broker app that resolves workspace tooling configuration and copies
# plugins dependencies to a workspace
che.workspace.plugin_broker.init.image=eclipse/che-init-plugin-broker:v0.24
che.workspace.plugin_broker.unified.image=eclipse/che-unified-plugin-broker:v0.24
che.workspace.plugin_broker.metadata.image=quay.io/eclipse/che-plugin-metadata-broker:v3.0.0
che.workspace.plugin_broker.artifacts.image=quay.io/eclipse/che-plugin-artifacts-broker:v3.0.0

# Docker image of Che plugin broker app that resolves workspace tooling configuration and copies
# plugins dependencies to a workspace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,20 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory;

/**
* Given a {@link InternalEnvironment} representing a workspace, adds the plugin broker as an init
* container to the workspace Pod. This is necessary if the workspace is created using emptyDir
* volumes (to allow the broker to add files to the workspace pod's volumes).
* Given a {@link InternalEnvironment} representing a workspace, adds the artifacts plugin broker as
* an init container to the workspace Pod in order to ensure that any extensions are downloaded.
*
* <p>This API is in <b>Beta</b> and is subject to changes or removal.
*
* @author Angel Misevski
*/
@Beta
public class KubernetesBrokerInitContainerApplier<E extends KubernetesEnvironment> {
public class KubernetesArtifactsBrokerApplier<E extends KubernetesEnvironment> {

private final BrokerEnvironmentFactory<E> brokerEnvironmentFactory;

@Inject
public KubernetesBrokerInitContainerApplier(
BrokerEnvironmentFactory<E> brokerEnvironmentFactory) {
public KubernetesArtifactsBrokerApplier(BrokerEnvironmentFactory<E> brokerEnvironmentFactory) {
this.brokerEnvironmentFactory = brokerEnvironmentFactory;
}

Expand All @@ -55,7 +53,7 @@ public void apply(
E workspaceEnvironment, RuntimeIdentity runtimeID, Collection<PluginFQN> pluginFQNs)
throws InfrastructureException {

E brokerEnvironment = brokerEnvironmentFactory.create(pluginFQNs, runtimeID);
E brokerEnvironment = brokerEnvironmentFactory.createForArtifactsBroker(pluginFQNs, runtimeID);

Map<String, PodData> workspacePods = workspaceEnvironment.getPodsData();
if (workspacePods.size() != 1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public List<ChePlugin> getTooling(
KubernetesNamespace kubernetesNamespace = factory.getOrCreate(identity);
BrokersResult brokersResult = new BrokersResult();

E brokerEnvironment = brokerEnvironmentFactory.create(pluginFQNs, identity);
E brokerEnvironment = brokerEnvironmentFactory.createForMetadataBroker(pluginFQNs, identity);
if (isEphemeral) {
EphemeralWorkspaceUtility.makeEphemeral(brokerEnvironment.getAttributes());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ public class SidecarToolingProvisioner<E extends KubernetesEnvironment> {
private static final Logger LOG = LoggerFactory.getLogger(SidecarToolingProvisioner.class);

private final Map<String, ChePluginsApplier> workspaceNextAppliers;
private final KubernetesBrokerInitContainerApplier<E> brokerApplier;
private final KubernetesArtifactsBrokerApplier<E> artifactsBrokerApplier;
private final PluginFQNParser pluginFQNParser;
private final PluginBrokerManager<E> pluginBrokerManager;

@Inject
public SidecarToolingProvisioner(
Map<String, ChePluginsApplier> workspaceNextAppliers,
KubernetesBrokerInitContainerApplier<E> brokerApplier,
KubernetesArtifactsBrokerApplier<E> artifactsBrokerApplier,
PluginFQNParser pluginFQNParser,
PluginBrokerManager<E> pluginBrokerManager) {
this.workspaceNextAppliers = ImmutableMap.copyOf(workspaceNextAppliers);
this.brokerApplier = brokerApplier;
this.artifactsBrokerApplier = artifactsBrokerApplier;
this.pluginFQNParser = pluginFQNParser;
this.pluginBrokerManager = pluginBrokerManager;
}
Expand Down Expand Up @@ -80,9 +80,7 @@ public void provision(
pluginBrokerManager.getTooling(identity, startSynchronizer, pluginFQNs, isEphemeral);

pluginsApplier.apply(identity, environment, chePlugins);
if (isEphemeral) {
brokerApplier.apply(environment, identity, pluginFQNs);
}
artifactsBrokerApplier.apply(environment, identity, pluginFQNs);
LOG.debug("Finished sidecar tooling provisioning workspace '{}'", identity.getWorkspaceId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.PodBuilder;
import io.fabric8.kubernetes.api.model.PodSpec;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.VolumeBuilder;
import io.fabric8.kubernetes.api.model.VolumeMount;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -77,8 +76,8 @@ public abstract class BrokerEnvironmentFactory<E extends KubernetesEnvironment>
private final String brokerPullPolicy;
private final AgentAuthEnableEnvVarProvider authEnableEnvVarProvider;
private final MachineTokenEnvVarProvider machineTokenEnvVarProvider;
private final String unifiedBrokerImage;
private final String initBrokerImage;
private final String artifactsBrokerImage;
private final String metadataBrokerImage;
private final String pluginRegistryUrl;
private final CertificateProvisioner certProvisioner;

Expand All @@ -87,81 +86,82 @@ public BrokerEnvironmentFactory(
String brokerPullPolicy,
AgentAuthEnableEnvVarProvider authEnableEnvVarProvider,
MachineTokenEnvVarProvider machineTokenEnvVarProvider,
String unifiedBrokerImage,
String initBrokerImage,
String artifactsBrokerImage,
String metadataBrokerImage,
String pluginRegistryUrl,
CertificateProvisioner certProvisioner) {
this.cheWebsocketEndpoint = cheWebsocketEndpoint;
this.brokerPullPolicy = brokerPullPolicy;
this.authEnableEnvVarProvider = authEnableEnvVarProvider;
this.machineTokenEnvVarProvider = machineTokenEnvVarProvider;
this.unifiedBrokerImage = unifiedBrokerImage;
this.initBrokerImage = initBrokerImage;
this.artifactsBrokerImage = artifactsBrokerImage;
this.metadataBrokerImage = metadataBrokerImage;
this.pluginRegistryUrl = pluginRegistryUrl;
this.certProvisioner = certProvisioner;
}

/**
* Creates {@link KubernetesEnvironment} with everything needed to deploy Plugin broker.
* Creates {@link KubernetesEnvironment} with everything needed to deploy metadata plugin broker.
*
* @param pluginFQNs fully qualified names of plugins that needs to be resolved by the broker
* @param runtimeID ID of the runtime the broker would be started
* @return kubernetes environment (or its extension) with the Plugin broker objects
*/
public E create(Collection<PluginFQN> pluginFQNs, RuntimeIdentity runtimeID)
public E createForMetadataBroker(Collection<PluginFQN> pluginFQNs, RuntimeIdentity runtimeID)
throws InfrastructureException {
BrokersConfigs brokersConfigs = getBrokersConfigs(pluginFQNs, runtimeID, metadataBrokerImage);
return doCreate(brokersConfigs);
}

/**
* Creates {@link KubernetesEnvironment} with everything needed to deploy artifacts plugin broker.
*
* @param pluginFQNs fully qualified names of plugins that needs to be resolved by the broker
* @param runtimeID ID of the runtime the broker would be started
* @return kubernetes environment (or its extension) with the Plugin broker objects
*/
public E createForArtifactsBroker(Collection<PluginFQN> pluginFQNs, RuntimeIdentity runtimeID)
throws InfrastructureException {
BrokersConfigs brokersConfigs = getBrokersConfigs(pluginFQNs, runtimeID, artifactsBrokerImage);
brokersConfigs
.machines
.values()
.forEach(
m -> m.getVolumes().put(PLUGINS_VOLUME_NAME, new VolumeImpl().withPath("/plugins")));
return doCreate(brokersConfigs);
}

private BrokersConfigs getBrokersConfigs(
Collection<PluginFQN> pluginFQNs, RuntimeIdentity runtimeID, String brokerImage)
throws InfrastructureException {

BrokersConfigs brokersConfigs = new BrokersConfigs();
Pod pod = brokersConfigs.pod = newPod();
brokersConfigs.configMaps = new HashMap<>();
brokersConfigs.machines = new HashMap<>();
String configMapName = generateUniqueName(CONFIG_MAP_NAME_SUFFIX);
String configMapVolume = generateUniqueName(BROKER_VOLUME);
ConfigMap configMap = newConfigMap(configMapName, pluginFQNs);

PodSpec spec = pod.getSpec();
Pod pod = newPod();
List<EnvVar> envVars =
Stream.of(
authEnableEnvVarProvider.get(runtimeID), machineTokenEnvVarProvider.get(runtimeID))
.map(this::asEnvVar)
.collect(Collectors.toList());
Container container = newContainer(runtimeID, envVars, brokerImage, configMapVolume);
pod.getSpec().getContainers().add(container);
pod.getSpec().getVolumes().add(newConfigMapVolume(configMapName, configMapVolume));

BrokerConfig brokerConfig =
createBrokerConfig(runtimeID, pluginFQNs, envVars, unifiedBrokerImage, pod);
brokersConfigs.machines.put(brokerConfig.machineName, brokerConfig.machineConfig);
brokersConfigs.configMaps.put(brokerConfig.configMapName, brokerConfig.configMap);
spec.getContainers().add(brokerConfig.container);
spec.getVolumes()
.add(
new VolumeBuilder()
.withName(brokerConfig.configMapVolume)
.withNewConfigMap()
.withName(brokerConfig.configMapName)
.endConfigMap()
.build());
InternalMachineConfig machineConfig = new InternalMachineConfig();
String machineName = Names.machineName(pod.getMetadata(), container);

// Add init broker that cleans up /plugins
BrokerConfig initBrokerConfig =
createBrokerConfig(runtimeID, null, envVars, initBrokerImage, pod);
pod.getSpec().getInitContainers().add(initBrokerConfig.container);
brokersConfigs.machines.put(initBrokerConfig.machineName, initBrokerConfig.machineConfig);
BrokersConfigs configs = new BrokersConfigs();
configs.configMaps = singletonMap(configMapName, configMap);
configs.machines = singletonMap(machineName, machineConfig);
configs.pods = singletonMap(pod.getMetadata().getName(), pod);

return doCreate(brokersConfigs);
return configs;
}

/** Needed to implement this component in both - Kubernetes and Openshift infrastructures. */
protected abstract E doCreate(BrokersConfigs brokersConfigs);

private String generateUniqueName(String suffix) {
return NameGenerator.generate(suffix, 6);
}

/**
* Generate a container name from an image reference. Since full image references can be over 63
* characters, we need to strip registry and organization from the image reference to limit name
* length.
*/
@VisibleForTesting
protected String generateContainerNameFromImageRef(String image) {
return image.toLowerCase().replaceAll("[^/]*/", "").replaceAll("[^\\d\\w-]", "-");
}
protected abstract E doCreate(BrokersConfigs brokerConfigs);

private Container newContainer(
RuntimeIdentity runtimeId,
Expand Down Expand Up @@ -223,51 +223,36 @@ private ConfigMap newConfigMap(String configMapName, Collection<PluginFQN> plugi
}
}

private Volume newConfigMapVolume(String configMapName, String configMapVolume) {
return new VolumeBuilder()
.withName(configMapVolume)
.withNewConfigMap()
.withName(configMapName)
.endConfigMap()
.build();
}

private EnvVar asEnvVar(Pair<String, String> envVar) {
return new EnvVarBuilder().withName(envVar.first).withValue(envVar.second).build();
}

private BrokerConfig createBrokerConfig(
RuntimeIdentity runtimeId,
@Nullable Collection<PluginFQN> pluginFQNs,
List<EnvVar> envVars,
String image,
Pod pod)
throws InternalInfrastructureException {

BrokerConfig brokerConfig = new BrokerConfig();
String configMapVolume = null;
if (pluginFQNs != null) {
brokerConfig.configMapName = generateUniqueName(CONFIG_MAP_NAME_SUFFIX);
brokerConfig.configMapVolume = generateUniqueName(BROKER_VOLUME);
brokerConfig.configMap = newConfigMap(brokerConfig.configMapName, pluginFQNs);
configMapVolume = brokerConfig.configMapVolume;
}
brokerConfig.container = newContainer(runtimeId, envVars, image, configMapVolume);
brokerConfig.machineName = Names.machineName(pod.getMetadata(), brokerConfig.container);
brokerConfig.machineConfig = new InternalMachineConfig();
brokerConfig
.machineConfig
.getVolumes()
.put(PLUGINS_VOLUME_NAME, new VolumeImpl().withPath("/plugins"));

return brokerConfig;
private String generateUniqueName(String suffix) {
return NameGenerator.generate(suffix, 6);
}

private static class BrokerConfig {

String configMapName;
ConfigMap configMap;
Container container;
String machineName;
InternalMachineConfig machineConfig;
String configMapVolume;
/**
* Generate a container name from an image reference. Since full image references can be over 63
* characters, we need to strip registry and organization from the image reference to limit name
* length.
*/
@VisibleForTesting
protected String generateContainerNameFromImageRef(String image) {
return image.toLowerCase().replaceAll("[^/]*/", "").replaceAll("[^\\d\\w-]", "-");
}

public static class BrokersConfigs {

public Map<String, InternalMachineConfig> machines;
public Map<String, ConfigMap> configMaps;
public Pod pod;
public Map<String, Pod> pods;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
*/
package org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases;

import static java.util.Collections.singletonMap;

import com.google.common.annotations.Beta;
import javax.inject.Inject;
import javax.inject.Named;
Expand All @@ -21,6 +19,7 @@
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.workspace.infrastructure.kubernetes.environment.KubernetesEnvironment;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.CertificateProvisioner;
import org.eclipse.che.workspace.infrastructure.kubernetes.wsplugins.brokerphases.BrokerEnvironmentFactory.BrokersConfigs;

/**
* Extends {@link BrokerEnvironmentFactory} to be used in the kubernetes infrastructure.
Expand All @@ -39,17 +38,17 @@ public KubernetesBrokerEnvironmentFactory(
@Named("che.workspace.plugin_broker.pull_policy") String brokerPullPolicy,
AgentAuthEnableEnvVarProvider authEnableEnvVarProvider,
MachineTokenEnvVarProvider machineTokenEnvVarProvider,
@Named("che.workspace.plugin_broker.init.image") String initBrokerImage,
@Named("che.workspace.plugin_broker.unified.image") String unifiedBrokerImage,
@Named("che.workspace.plugin_broker.artifacts.image") String artifactsBrokerImage,
@Named("che.workspace.plugin_broker.metadata.image") String metadataBrokerImage,
@Nullable @Named("che.workspace.plugin_registry_url") String pluginRegistryUrl,
CertificateProvisioner certProvisioner) {
super(
cheWebsocketEndpoint,
brokerPullPolicy,
authEnableEnvVarProvider,
machineTokenEnvVarProvider,
unifiedBrokerImage,
initBrokerImage,
artifactsBrokerImage,
metadataBrokerImage,
pluginRegistryUrl,
certProvisioner);
}
Expand All @@ -59,7 +58,7 @@ protected KubernetesEnvironment doCreate(BrokersConfigs brokersConfigs) {
return KubernetesEnvironment.builder()
.setConfigMaps(brokersConfigs.configMaps)
.setMachines(brokersConfigs.machines)
.setPods(singletonMap(brokersConfigs.pod.getMetadata().getName(), brokersConfigs.pod))
.setPods(brokersConfigs.pods)
.build();
}
}
Loading

0 comments on commit 8c27ba9

Please sign in to comment.