diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/sandbox')
5 files changed, 95 insertions, 240 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java index 7b132f124c..3574691243 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/DarwinSandboxedStrategy.java @@ -16,10 +16,8 @@ package com.google.devtools.build.lib.sandbox; import com.google.devtools.build.lib.actions.ExecutionStrategy; import com.google.devtools.build.lib.actions.SpawnActionContext; -import com.google.devtools.build.lib.buildtool.BuildRequest; -import com.google.devtools.build.lib.runtime.CommandEnvironment; -import com.google.devtools.build.lib.vfs.Path; -import java.io.IOException; +import com.google.devtools.build.lib.exec.AbstractSpawnStrategy; +import com.google.devtools.build.lib.exec.SpawnRunner; /** Strategy that uses sandboxing to execute a process, for Darwin */ //TODO(ulfjack): This class only exists for this annotation. Find a better way to handle this! @@ -27,18 +25,13 @@ import java.io.IOException; name = {"sandboxed", "darwin-sandbox"}, contextType = SpawnActionContext.class ) -final class DarwinSandboxedStrategy extends SandboxStrategy { - DarwinSandboxedStrategy( - CommandEnvironment cmdEnv, - BuildRequest buildRequest, - Path sandboxBase, - boolean verboseFailures, - String productName, - int timeoutGraceSeconds) - throws IOException { - super( - verboseFailures, - new DarwinSandboxedSpawnRunner( - cmdEnv, buildRequest, sandboxBase, productName, timeoutGraceSeconds)); +final class DarwinSandboxedStrategy extends AbstractSpawnStrategy { + DarwinSandboxedStrategy(boolean verboseFailures, SpawnRunner spawnRunner) { + super(verboseFailures, spawnRunner); + } + + @Override + public String toString() { + return "sandboxed"; } } diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java index 5e4cf5dd10..f344708d90 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedStrategy.java @@ -17,6 +17,8 @@ package com.google.devtools.build.lib.sandbox; import com.google.devtools.build.lib.actions.ExecutionStrategy; import com.google.devtools.build.lib.actions.SpawnActionContext; import com.google.devtools.build.lib.buildtool.BuildRequest; +import com.google.devtools.build.lib.exec.AbstractSpawnStrategy; +import com.google.devtools.build.lib.exec.SpawnRunner; import com.google.devtools.build.lib.runtime.CommandEnvironment; import com.google.devtools.build.lib.vfs.FileSystemUtils; import com.google.devtools.build.lib.vfs.Path; @@ -28,33 +30,22 @@ import java.io.IOException; name = {"sandboxed", "linux-sandbox"}, contextType = SpawnActionContext.class ) -public final class LinuxSandboxedStrategy extends SandboxStrategy { - private LinuxSandboxedStrategy( - CommandEnvironment cmdEnv, - BuildRequest buildRequest, - Path sandboxBase, - boolean verboseFailures, - Path inaccessibleHelperFile, - Path inaccessibleHelperDir, - int timeoutGraceSeconds) { - super( - verboseFailures, - new LinuxSandboxedSpawnRunner( - cmdEnv, - buildRequest, - sandboxBase, - inaccessibleHelperFile, - inaccessibleHelperDir, - timeoutGraceSeconds)); +public final class LinuxSandboxedStrategy extends AbstractSpawnStrategy { + LinuxSandboxedStrategy(boolean verboseFailures, SpawnRunner spawnRunner) { + super(verboseFailures, spawnRunner); + } + + @Override + public String toString() { + return "sandboxed"; } - static LinuxSandboxedStrategy create( + static LinuxSandboxedSpawnRunner create( CommandEnvironment cmdEnv, BuildRequest buildRequest, Path sandboxBase, - boolean verboseFailures, int timeoutGraceSeconds) - throws IOException { + throws IOException { Path inaccessibleHelperFile = sandboxBase.getRelative("inaccessibleHelperFile"); FileSystemUtils.touchFile(inaccessibleHelperFile); inaccessibleHelperFile.setReadable(false); @@ -67,11 +58,10 @@ public final class LinuxSandboxedStrategy extends SandboxStrategy { inaccessibleHelperDir.setWritable(false); inaccessibleHelperDir.setExecutable(false); - return new LinuxSandboxedStrategy( + return new LinuxSandboxedSpawnRunner( cmdEnv, buildRequest, sandboxBase, - verboseFailures, inaccessibleHelperFile, inaccessibleHelperDir, timeoutGraceSeconds); diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java index af4ae92e48..202f586065 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/ProcessWrapperSandboxedStrategy.java @@ -16,9 +16,8 @@ package com.google.devtools.build.lib.sandbox; import com.google.devtools.build.lib.actions.ExecutionStrategy; import com.google.devtools.build.lib.actions.SpawnActionContext; -import com.google.devtools.build.lib.buildtool.BuildRequest; -import com.google.devtools.build.lib.runtime.CommandEnvironment; -import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.exec.AbstractSpawnStrategy; +import com.google.devtools.build.lib.exec.SpawnRunner; /** Strategy that uses sandboxing to execute a process. */ //TODO(ulfjack): This class only exists for this annotation. Find a better way to handle this! @@ -26,17 +25,13 @@ import com.google.devtools.build.lib.vfs.Path; name = {"sandboxed", "processwrapper-sandbox"}, contextType = SpawnActionContext.class ) -final class ProcessWrapperSandboxedStrategy extends SandboxStrategy { - ProcessWrapperSandboxedStrategy( - CommandEnvironment cmdEnv, - BuildRequest buildRequest, - Path sandboxBase, - boolean verboseFailures, - String productName, - int timeoutGraceSeconds) { - super( - verboseFailures, - new ProcessWrapperSandboxedSpawnRunner( - cmdEnv, buildRequest, sandboxBase, productName, timeoutGraceSeconds)); +final class ProcessWrapperSandboxedStrategy extends AbstractSpawnStrategy { + ProcessWrapperSandboxedStrategy(boolean verboseFailures, SpawnRunner spawnRunner) { + super(verboseFailures, spawnRunner); + } + + @Override + public String toString() { + return "sandboxed"; } } diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java index 4f795f4059..55f755da4c 100644 --- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java +++ b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxActionContextProvider.java @@ -16,11 +16,20 @@ package com.google.devtools.build.lib.sandbox; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.ActionContext; +import com.google.devtools.build.lib.actions.ExecException; +import com.google.devtools.build.lib.actions.ResourceManager; +import com.google.devtools.build.lib.actions.Spawn; import com.google.devtools.build.lib.buildtool.BuildRequest; import com.google.devtools.build.lib.exec.ActionContextProvider; import com.google.devtools.build.lib.exec.ExecutionOptions; +import com.google.devtools.build.lib.exec.SpawnResult; +import com.google.devtools.build.lib.exec.SpawnRunner; +import com.google.devtools.build.lib.exec.apple.XCodeLocalEnvProvider; +import com.google.devtools.build.lib.exec.local.LocalEnvProvider; import com.google.devtools.build.lib.exec.local.LocalExecutionOptions; +import com.google.devtools.build.lib.exec.local.LocalSpawnRunner; import com.google.devtools.build.lib.runtime.CommandEnvironment; +import com.google.devtools.build.lib.util.OS; import com.google.devtools.build.lib.vfs.Path; import java.io.IOException; @@ -46,40 +55,74 @@ final class SandboxActionContextProvider extends ActionContextProvider { // This works on most platforms, but isn't the best choice, so we put it first and let later // platform-specific sandboxing strategies become the default. if (ProcessWrapperSandboxedSpawnRunner.isSupported(cmdEnv)) { - contexts.add( - new ProcessWrapperSandboxedStrategy( - cmdEnv, - buildRequest, - sandboxBase, - verboseFailures, - productName, - timeoutGraceSeconds)); + SpawnRunner spawnRunner = withFallback( + cmdEnv, + new ProcessWrapperSandboxedSpawnRunner( + cmdEnv, buildRequest, sandboxBase, productName, timeoutGraceSeconds)); + contexts.add(new ProcessWrapperSandboxedStrategy(verboseFailures, spawnRunner)); } // This is the preferred sandboxing strategy on Linux. if (LinuxSandboxedSpawnRunner.isSupported(cmdEnv)) { - contexts.add( - LinuxSandboxedStrategy.create( - cmdEnv, buildRequest, sandboxBase, verboseFailures, timeoutGraceSeconds)); + SpawnRunner spawnRunner = withFallback( + cmdEnv, + LinuxSandboxedStrategy.create(cmdEnv, buildRequest, sandboxBase, timeoutGraceSeconds)); + contexts.add(new LinuxSandboxedStrategy(verboseFailures, spawnRunner)); } // This is the preferred sandboxing strategy on macOS. if (DarwinSandboxedSpawnRunner.isSupported(cmdEnv)) { - contexts.add( - new DarwinSandboxedStrategy( - cmdEnv, - buildRequest, - sandboxBase, - verboseFailures, - productName, - timeoutGraceSeconds)); + SpawnRunner spawnRunner = withFallback( + cmdEnv, + new DarwinSandboxedSpawnRunner( + cmdEnv, buildRequest, sandboxBase, productName, timeoutGraceSeconds)); + contexts.add(new DarwinSandboxedStrategy(verboseFailures, spawnRunner)); } return new SandboxActionContextProvider(contexts.build()); } + private static SpawnRunner withFallback(CommandEnvironment env, SpawnRunner sandboxSpawnRunner) { + return new SandboxFallbackSpawnRunner(sandboxSpawnRunner, createFallbackRunner(env)); + } + + private static SpawnRunner createFallbackRunner(CommandEnvironment env) { + LocalExecutionOptions localExecutionOptions = + env.getOptions().getOptions(LocalExecutionOptions.class); + LocalEnvProvider localEnvProvider = OS.getCurrent() == OS.DARWIN + ? new XCodeLocalEnvProvider() + : LocalEnvProvider.UNMODIFIED; + return + new LocalSpawnRunner( + env.getExecRoot(), + localExecutionOptions, + ResourceManager.instance(), + env.getRuntime().getProductName(), + localEnvProvider); + } + @Override public Iterable<? extends ActionContext> getActionContexts() { return contexts; } + + private static final class SandboxFallbackSpawnRunner implements SpawnRunner { + private final SpawnRunner sandboxSpawnRunner; + private final SpawnRunner fallbackSpawnRunner; + + SandboxFallbackSpawnRunner(SpawnRunner sandboxSpawnRunner, SpawnRunner fallbackSpawnRunner) { + this.sandboxSpawnRunner = sandboxSpawnRunner; + this.fallbackSpawnRunner = fallbackSpawnRunner; + } + + @Override + public SpawnResult exec(Spawn spawn, SpawnExecutionPolicy policy) + throws InterruptedException, IOException, ExecException { + if (!spawn.isRemotable() || spawn.hasNoSandbox()) { + return fallbackSpawnRunner.exec(spawn, policy); + } else { + return sandboxSpawnRunner.exec(spawn, policy); + } + } + } } diff --git a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxStrategy.java b/src/main/java/com/google/devtools/build/lib/sandbox/SandboxStrategy.java deleted file mode 100644 index e64a795f03..0000000000 --- a/src/main/java/com/google/devtools/build/lib/sandbox/SandboxStrategy.java +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2016 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.eventbus.EventBus; -import com.google.devtools.build.lib.actions.ActionExecutionContext; -import com.google.devtools.build.lib.actions.ActionInput; -import com.google.devtools.build.lib.actions.ActionInputFileCache; -import com.google.devtools.build.lib.actions.ActionInputPrefetcher; -import com.google.devtools.build.lib.actions.ActionStatusMessage; -import com.google.devtools.build.lib.actions.Artifact.ArtifactExpander; -import com.google.devtools.build.lib.actions.ExecException; -import com.google.devtools.build.lib.actions.SandboxedSpawnActionContext; -import com.google.devtools.build.lib.actions.Spawn; -import com.google.devtools.build.lib.actions.SpawnActionContext; -import com.google.devtools.build.lib.actions.Spawns; -import com.google.devtools.build.lib.exec.SpawnExecException; -import com.google.devtools.build.lib.exec.SpawnInputExpander; -import com.google.devtools.build.lib.exec.SpawnResult; -import com.google.devtools.build.lib.exec.SpawnResult.Status; -import com.google.devtools.build.lib.exec.SpawnRunner.ProgressStatus; -import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionPolicy; -import com.google.devtools.build.lib.rules.fileset.FilesetActionContext; -import com.google.devtools.build.lib.util.CommandFailureUtils; -import com.google.devtools.build.lib.util.io.FileOutErr; -import com.google.devtools.build.lib.vfs.PathFragment; -import java.io.IOException; -import java.util.SortedMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -/** Abstract common ancestor for sandbox strategies implementing the common parts. */ -abstract class SandboxStrategy implements SandboxedSpawnActionContext { - private final boolean verboseFailures; - private final SpawnInputExpander spawnInputExpander; - private final AbstractSandboxSpawnRunner spawnRunner; - private final ActionInputPrefetcher inputPrefetcher; - private final AtomicInteger execCount = new AtomicInteger(); - - public SandboxStrategy( - boolean verboseFailures, - AbstractSandboxSpawnRunner spawnRunner) { - this.verboseFailures = verboseFailures; - this.spawnInputExpander = new SpawnInputExpander(false); - this.spawnRunner = spawnRunner; - this.inputPrefetcher = ActionInputPrefetcher.NONE; - } - - @Override - public void exec(Spawn spawn, ActionExecutionContext actionExecutionContext) - throws ExecException, InterruptedException { - exec(spawn, actionExecutionContext, null); - } - - @Override - public void exec( - Spawn spawn, - ActionExecutionContext actionExecutionContext, - AtomicReference<Class<? extends SpawnActionContext>> writeOutputFiles) - throws ExecException, InterruptedException { - // Certain actions can't run remotely or in a sandbox - pass them on to the standalone strategy. - if (!spawn.isRemotable() || spawn.hasNoSandbox()) { - SandboxHelpers.fallbackToNonSandboxedExecution(spawn, actionExecutionContext); - return; - } - - if (actionExecutionContext.reportsSubcommands()) { - actionExecutionContext.reportSubcommand(spawn); - } - final int timeoutSeconds = Spawns.getTimeoutSeconds(spawn); - SpawnExecutionPolicy policy = new SpawnExecutionPolicy() { - private final int id = execCount.incrementAndGet(); - - @Override - public int getId() { - return id; - } - - @Override - public void prefetchInputs(Iterable<ActionInput> inputs) throws IOException { - inputPrefetcher.prefetchFiles(inputs); - } - - @Override - public ActionInputFileCache getActionInputFileCache() { - return actionExecutionContext.getActionInputFileCache(); - } - - @Override - public ArtifactExpander getArtifactExpander() { - return actionExecutionContext.getArtifactExpander(); - } - - @Override - public void lockOutputFiles() throws InterruptedException { - Class<? extends SpawnActionContext> token = SandboxStrategy.this.getClass(); - if (writeOutputFiles != null - && writeOutputFiles.get() != token - && !writeOutputFiles.compareAndSet(null, token)) { - throw new InterruptedException(); - } - } - - @Override - public long getTimeoutMillis() { - return TimeUnit.SECONDS.toMillis(timeoutSeconds); - } - - @Override - public FileOutErr getFileOutErr() { - return actionExecutionContext.getFileOutErr(); - } - - @Override - public SortedMap<PathFragment, ActionInput> getInputMapping() throws IOException { - return spawnInputExpander.getInputMapping( - spawn, - actionExecutionContext.getArtifactExpander(), - actionExecutionContext.getActionInputFileCache(), - actionExecutionContext.getContext(FilesetActionContext.class)); - } - - @Override - public void report(ProgressStatus state, String name) { - // TODO(ulfjack): We should report more details to the UI. - EventBus eventBus = actionExecutionContext.getEventBus(); - switch (state) { - case EXECUTING: - eventBus.post(ActionStatusMessage.runningStrategy(spawn.getResourceOwner(), name)); - break; - case SCHEDULING: - eventBus.post(ActionStatusMessage.schedulingStrategy(spawn.getResourceOwner())); - break; - default: - break; - } - } - }; - SpawnResult result = spawnRunner.exec(spawn, policy); - if (result.status() != Status.SUCCESS || result.exitCode() != 0) { - String message = - CommandFailureUtils.describeCommandFailure( - verboseFailures, spawn.getArguments(), spawn.getEnvironment(), null); - throw new SpawnExecException( - message, result, /*forciblyRunRemotely=*/false, /*catastrophe=*/false); - } - } - - @Override - public String toString() { - return "sandboxed"; - } -} |