Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP Work around arbitrary user IDs on OpenShift #13561

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.restartpolicy.RestartPolicyRewriter;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.server.ServersConverter;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.provision.OpenShiftCommandProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.OpenShiftUniqueNamesProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.RouteTlsProvisioner;
import org.slf4j.Logger;
Expand Down Expand Up @@ -66,6 +67,7 @@ public class OpenShiftEnvironmentProvisioner
private final ProxySettingsProvisioner proxySettingsProvisioner;
private final ServiceAccountProvisioner serviceAccountProvisioner;
private final CertificateProvisioner certificateProvisioner;
private final OpenShiftCommandProvisioner commandProvisioner;

@Inject
public OpenShiftEnvironmentProvisioner(
Expand All @@ -83,7 +85,8 @@ public OpenShiftEnvironmentProvisioner(
ImagePullSecretProvisioner imagePullSecretProvisioner,
ProxySettingsProvisioner proxySettingsProvisioner,
ServiceAccountProvisioner serviceAccountProvisioner,
CertificateProvisioner certificateProvisioner) {
CertificateProvisioner certificateProvisioner,
OpenShiftCommandProvisioner commandProvisioner) {
this.pvcEnabled = pvcEnabled;
this.volumesStrategy = volumesStrategy;
this.uniqueNamesProvisioner = uniqueNamesProvisioner;
Expand All @@ -99,6 +102,7 @@ public OpenShiftEnvironmentProvisioner(
this.proxySettingsProvisioner = proxySettingsProvisioner;
this.serviceAccountProvisioner = serviceAccountProvisioner;
this.certificateProvisioner = certificateProvisioner;
this.commandProvisioner = commandProvisioner;
}

@Override
Expand Down Expand Up @@ -133,6 +137,7 @@ public void provision(OpenShiftEnvironment osEnv, RuntimeIdentity identity)
proxySettingsProvisioner.provision(osEnv, identity);
serviceAccountProvisioner.provision(osEnv, identity);
certificateProvisioner.provision(osEnv, identity);
commandProvisioner.provision(osEnv, identity);
LOG.debug(
"Provisioning OpenShift environment done for workspace '{}'", identity.getWorkspaceId());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.openshift.provision;

import static org.eclipse.che.api.workspace.shared.Constants.ARBITRARY_USER_ATTRIBUTE;
import static org.eclipse.che.api.workspace.shared.Constants.CONTAINER_SOURCE_ATTRIBUTE;
import static org.eclipse.che.api.workspace.shared.Constants.RECIPE_CONTAINER_SOURCE;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import io.fabric8.kubernetes.api.model.Container;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.stream.Collectors;
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.PodData;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.ConfigurationProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;

public class OpenShiftCommandProvisioner implements ConfigurationProvisioner<OpenShiftEnvironment> {

@VisibleForTesting protected static final List<String> SHELL_BINARY = ImmutableList.of("/bin/sh");
@VisibleForTesting protected static final String SHELL_ARGS = "-c";

@VisibleForTesting
protected static final String ADD_USER_COMMAND =
"if ! whoami &> /dev/null && [ -w /etc/passwd ]; then "
+ "echo \"user:x:$(id -u):0:user user:projects/:/bin/bash\" >> /etc/passwd;"
+ "fi;";

@VisibleForTesting protected static final String COMMAND_FORMAT = "%s %s %s";

@Override
public void provision(OpenShiftEnvironment osEnv, RuntimeIdentity identity)
throws InfrastructureException {

if (!supportArbitraryUser(osEnv.getAttributes())) {
return;
}

Set<String> recipeMachineNames =
osEnv
.getMachines()
.entrySet()
.stream()
.filter(
e ->
RECIPE_CONTAINER_SOURCE.equals(
e.getValue().getAttributes().get(CONTAINER_SOURCE_ATTRIBUTE)))
.map(Entry::getKey)
.collect(Collectors.toSet());

for (PodData podData : osEnv.getPodsData().values()) {
for (Container container : podData.getSpec().getContainers()) {
String machineName = Names.machineName(podData, container);
if (recipeMachineNames.contains(machineName)) {
rewriteContainerCommand(container);
}
}
}
}

private void rewriteContainerCommand(Container container) {
List<String> defaultCommand = container.getCommand();
List<String> defaultArgs = container.getArgs();

if (defaultCommand == null || defaultCommand.size() == 0) {
return;
}

String script =
String.format(
COMMAND_FORMAT,
ADD_USER_COMMAND,
String.join(" ", defaultCommand),
String.join(" ", defaultArgs));
container.setCommand(SHELL_BINARY);
container.setArgs(ImmutableList.of(SHELL_ARGS, script));
}

private boolean supportArbitraryUser(Map<String, String> workspaceAttributes) {
String supportArbitraryUser = workspaceAttributes.get(ARBITRARY_USER_ATTRIBUTE);
return "true".equals(supportArbitraryUser);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.restartpolicy.RestartPolicyRewriter;
import org.eclipse.che.workspace.infrastructure.kubernetes.provision.server.ServersConverter;
import org.eclipse.che.workspace.infrastructure.openshift.environment.OpenShiftEnvironment;
import org.eclipse.che.workspace.infrastructure.openshift.provision.OpenShiftCommandProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.OpenShiftUniqueNamesProvisioner;
import org.eclipse.che.workspace.infrastructure.openshift.provision.RouteTlsProvisioner;
import org.mockito.InOrder;
Expand Down Expand Up @@ -61,6 +62,7 @@ public class OpenShiftEnvironmentProvisionerTest {
@Mock private ProxySettingsProvisioner proxySettingsProvisioner;
@Mock private ServiceAccountProvisioner serviceAccountProvisioner;
@Mock private CertificateProvisioner certificateProvisioner;
@Mock private OpenShiftCommandProvisioner commandProvisioner;

private OpenShiftEnvironmentProvisioner osInfraProvisioner;

Expand All @@ -84,7 +86,8 @@ public void setUp() {
imagePullSecretProvisioner,
proxySettingsProvisioner,
serviceAccountProvisioner,
certificateProvisioner);
certificateProvisioner,
commandProvisioner);
provisionOrder =
inOrder(
installerServersPortProvisioner,
Expand All @@ -100,7 +103,8 @@ public void setUp() {
imagePullSecretProvisioner,
proxySettingsProvisioner,
serviceAccountProvisioner,
certificateProvisioner);
certificateProvisioner,
commandProvisioner);
}

@Test
Expand All @@ -125,6 +129,7 @@ public void performsOrderedProvisioning() throws Exception {
provisionOrder.verify(proxySettingsProvisioner).provision(eq(osEnv), eq(runtimeIdentity));
provisionOrder.verify(serviceAccountProvisioner).provision(eq(osEnv), eq(runtimeIdentity));
provisionOrder.verify(certificateProvisioner).provision(eq(osEnv), eq(runtimeIdentity));
provisionOrder.verify(commandProvisioner).provision(eq(osEnv), eq(runtimeIdentity));
provisionOrder.verifyNoMoreInteractions();
}
}
Loading