| // 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.ProcessWrapperUtil; |
| import com.google.devtools.build.lib.vfs.Path; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import java.time.Duration; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.UUID; |
| |
| final class DockerCommandLineBuilder { |
| private Path processWrapper; |
| private Path dockerClient; |
| private String imageName; |
| private List<String> commandArguments; |
| private Path sandboxExecRoot; |
| private Map<String, String> environmentVariables; |
| private Duration timeout; |
| private Duration killDelay; |
| 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; |
| |
| public DockerCommandLineBuilder setProcessWrapper(Path processWrapper) { |
| this.processWrapper = processWrapper; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setDockerClient(Path dockerClient) { |
| this.dockerClient = dockerClient; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setImageName(String imageName) { |
| this.imageName = imageName; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setCommandArguments(List<String> commandArguments) { |
| this.commandArguments = commandArguments; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setSandboxExecRoot(Path sandboxExecRoot) { |
| this.sandboxExecRoot = sandboxExecRoot; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setEnvironmentVariables( |
| Map<String, String> environmentVariables) { |
| this.environmentVariables = environmentVariables; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setTimeout(Duration timeout) { |
| this.timeout = timeout; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setKillDelay(Duration killDelay) { |
| this.killDelay = killDelay; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setCreateNetworkNamespace(boolean createNetworkNamespace) { |
| this.createNetworkNamespace = createNetworkNamespace; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setUuid(UUID uuid) { |
| this.uuid = uuid; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setUid(int uid) { |
| this.uid = uid; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setGid(int gid) { |
| this.gid = gid; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setCommandId(String commandId) { |
| this.commandId = commandId; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setPrivileged(boolean privileged) { |
| this.privileged = privileged; |
| return this; |
| } |
| |
| public DockerCommandLineBuilder setAdditionalMounts( |
| List<Map.Entry<String, String>> additionalMounts) { |
| this.additionalMounts = additionalMounts; |
| return this; |
| } |
| |
| public List<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"); |
| } |
| for (Map.Entry<String, String> env : environmentVariables.entrySet()) { |
| dockerCmdLine.add("-e", env.getKey() + "=" + env.getValue()); |
| } |
| 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); |
| |
| ProcessWrapperUtil.CommandLineBuilder processWrapperCmdLine = |
| ProcessWrapperUtil.commandLineBuilder( |
| this.processWrapper.getPathString(), dockerCmdLine.build()); |
| if (timeout != null) { |
| processWrapperCmdLine.setTimeout(timeout); |
| } |
| if (killDelay != null) { |
| processWrapperCmdLine.setKillDelay(killDelay); |
| } |
| return processWrapperCmdLine.build(); |
| } |
| } |