// 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.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 commandArguments; private Path sandboxExecRoot; private Map 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; 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 commandArguments) { this.commandArguments = commandArguments; return this; } public DockerCommandLineBuilder setSandboxExecRoot(Path sandboxExecRoot) { this.sandboxExecRoot = sandboxExecRoot; return this; } public DockerCommandLineBuilder setEnvironmentVariables( Map 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 List 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 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 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()); 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(); } }