blob: 387fa0841a3d80d6ee8d2a782ec1db9063d13aa7 [file] [log] [blame]
// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.sandbox;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.runtime.ProcessWrapper;
import com.google.devtools.build.lib.vfs.Path;
import com.google.devtools.build.lib.vfs.PathFragment;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.time.Duration;
import java.util.List;
import java.util.Map;
import java.util.UUID;
final class DockerCommandLineBuilder {
private ProcessWrapper processWrapper;
private Path dockerClient;
private String imageName;
private List<String> commandArguments;
private Path sandboxExecRoot;
private Map<String, String> environmentVariables;
private Duration timeout;
private boolean createNetworkNamespace;
private UUID uuid;
private int uid;
private int gid;
private String commandId;
private boolean privileged;
private List<Map.Entry<String, String>> additionalMounts;
@CanIgnoreReturnValue
public DockerCommandLineBuilder setProcessWrapper(ProcessWrapper processWrapper) {
this.processWrapper = processWrapper;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setDockerClient(Path dockerClient) {
this.dockerClient = dockerClient;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setImageName(String imageName) {
this.imageName = imageName;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setCommandArguments(List<String> commandArguments) {
this.commandArguments = commandArguments;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setSandboxExecRoot(Path sandboxExecRoot) {
this.sandboxExecRoot = sandboxExecRoot;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setEnvironmentVariables(
Map<String, String> environmentVariables) {
this.environmentVariables = environmentVariables;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setTimeout(Duration timeout) {
this.timeout = timeout;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setCreateNetworkNamespace(boolean createNetworkNamespace) {
this.createNetworkNamespace = createNetworkNamespace;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setUuid(UUID uuid) {
this.uuid = uuid;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setUid(int uid) {
this.uid = uid;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setGid(int gid) {
this.gid = gid;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setCommandId(String commandId) {
this.commandId = commandId;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setPrivileged(boolean privileged) {
this.privileged = privileged;
return this;
}
@CanIgnoreReturnValue
public DockerCommandLineBuilder setAdditionalMounts(
List<Map.Entry<String, String>> additionalMounts) {
this.additionalMounts = additionalMounts;
return this;
}
public ImmutableList<String> build() {
Preconditions.checkNotNull(sandboxExecRoot, "sandboxExecRoot must be set");
Preconditions.checkState(!imageName.isEmpty(), "imageName must be set");
Preconditions.checkState(!commandArguments.isEmpty(), "commandArguments must be set");
ImmutableList.Builder<String> dockerCmdLine = ImmutableList.builder();
dockerCmdLine.add(dockerClient.getPathString());
dockerCmdLine.add("run");
dockerCmdLine.add("--rm");
if (createNetworkNamespace) {
dockerCmdLine.add("--network=none");
} else {
dockerCmdLine.add("--network=host");
}
if (privileged) {
dockerCmdLine.add("--privileged");
}
environmentVariables.forEach((k, v) -> dockerCmdLine.add("-e", k + "=" + v));
PathFragment execRootInsideDocker =
PathFragment.create("/execroot/").getRelative(sandboxExecRoot.getBaseName());
dockerCmdLine.add(
"-v", sandboxExecRoot.getPathString() + ":" + execRootInsideDocker.getPathString());
dockerCmdLine.add("-w", execRootInsideDocker.getPathString());
for (ImmutableMap.Entry<String, String> additionalMountPath : additionalMounts) {
final String mountTarget = additionalMountPath.getValue();
final String mountSource = additionalMountPath.getKey();
dockerCmdLine.add("-v", mountSource + ":" + mountTarget);
}
StringBuilder uidGidFlagBuilder = new StringBuilder();
if (uid != 0) {
uidGidFlagBuilder.append(uid);
}
if (gid != 0) {
uidGidFlagBuilder.append(":");
uidGidFlagBuilder.append(gid);
}
String uidGidFlag = uidGidFlagBuilder.toString();
if (!uidGidFlag.isEmpty()) {
dockerCmdLine.add("-u", uidGidFlagBuilder.toString());
}
if (!commandId.isEmpty()) {
dockerCmdLine.add("-l", "command_id=" + commandId);
}
if (uuid != null) {
dockerCmdLine.add("--name", uuid.toString());
}
dockerCmdLine.add(imageName);
dockerCmdLine.addAll(commandArguments);
ProcessWrapper.CommandLineBuilder processWrapperCmdLine =
processWrapper.commandLineBuilder(dockerCmdLine.build());
if (timeout != null) {
processWrapperCmdLine.setTimeout(timeout);
}
return processWrapperCmdLine.build();
}
}