Search in sources :

Example 11 with Executor

use of com.google.devtools.build.lib.actions.Executor in project bazel by bazelbuild.

the class StandaloneSpawnStrategy method actuallyExec.

/**
   * Executes the given {@code spawn}.
   */
private void actuallyExec(Spawn spawn, ActionExecutionContext actionExecutionContext) throws ExecException {
    Executor executor = actionExecutionContext.getExecutor();
    if (executor.reportsSubcommands()) {
        executor.reportSubcommand(spawn);
    }
    int timeoutSeconds = Spawns.getTimeoutSeconds(spawn);
    // We must wrap the subprocess with process-wrapper to kill the process tree.
    // All actions therefore depend on the process-wrapper file. Since it's embedded,
    // we don't bother with declaring it as an input.
    List<String> args = new ArrayList<>();
    if (OS.getCurrent() != OS.WINDOWS) {
        // TODO(bazel-team): process-wrapper seems to work on Windows, but requires
        // additional setup as it is an msys2 binary, so it needs msys2 DLLs on %PATH%.
        // Disable it for now to make the setup easier and to avoid further PATH hacks.
        // Ideally we should have a native implementation of process-wrapper for Windows.
        args.add(processWrapper.getPathString());
        args.add(Integer.toString(timeoutSeconds));
        args.add("5");
        /* kill delay: give some time to print stacktraces and whatnot. */
        // TODO(bazel-team): use process-wrapper redirection so we don't have to
        // pass test logs through the Java heap.
        args.add("-");
        /* stdout. */
        args.add("-");
    /* stderr. */
    }
    args.addAll(spawn.getArguments());
    String cwd = executor.getExecRoot().getPathString();
    Command cmd = new Command(args.toArray(new String[] {}), locallyDeterminedEnv(execRoot, productName, spawn.getEnvironment()), new File(cwd), OS.getCurrent() == OS.WINDOWS && timeoutSeconds >= 0 ? timeoutSeconds * 1000 : -1);
    FileOutErr outErr = actionExecutionContext.getFileOutErr();
    try {
        cmd.execute(/* stdin */
        new byte[] {}, Command.NO_OBSERVER, outErr.getOutputStream(), outErr.getErrorStream(), /*killSubprocessOnInterrupt*/
        true);
    } catch (AbnormalTerminationException e) {
        TerminationStatus status = e.getResult().getTerminationStatus();
        boolean timedOut = !status.exited() && (status.timedout() || status.getTerminatingSignal() == 14);
        String message = CommandFailureUtils.describeCommandFailure(verboseFailures, spawn.getArguments(), spawn.getEnvironment(), cwd);
        throw new UserExecException(String.format("%s: %s", message, e), timedOut);
    } catch (CommandException e) {
        String message = CommandFailureUtils.describeCommandFailure(verboseFailures, spawn.getArguments(), spawn.getEnvironment(), cwd);
        throw new UserExecException(message, e);
    }
}
Also used : Executor(com.google.devtools.build.lib.actions.Executor) FileOutErr(com.google.devtools.build.lib.util.io.FileOutErr) Command(com.google.devtools.build.lib.shell.Command) TerminationStatus(com.google.devtools.build.lib.shell.TerminationStatus) ArrayList(java.util.ArrayList) UserExecException(com.google.devtools.build.lib.actions.UserExecException) AbnormalTerminationException(com.google.devtools.build.lib.shell.AbnormalTerminationException) CommandException(com.google.devtools.build.lib.shell.CommandException) File(java.io.File)

Example 12 with Executor

use of com.google.devtools.build.lib.actions.Executor in project bazel by bazelbuild.

the class WorkerSpawnStrategy method actuallyExec.

private void actuallyExec(Spawn spawn, ActionExecutionContext actionExecutionContext, AtomicReference<Class<? extends SpawnActionContext>> writeOutputFiles) throws ExecException, InterruptedException {
    Executor executor = actionExecutionContext.getExecutor();
    EventHandler eventHandler = executor.getEventHandler();
    if (executor.reportsSubcommands()) {
        executor.reportSubcommand(spawn);
    }
    // We assume that the spawn to be executed always gets at least one @flagfile.txt or
    // --flagfile=flagfile.txt argument, which contains the flags related to the work itself (as
    // opposed to start-up options for the executed tool). Thus, we can extract those elements from
    // its args and put them into the WorkRequest instead.
    List<String> flagfiles = new ArrayList<>();
    List<String> startupArgs = new ArrayList<>();
    for (String arg : spawn.getArguments()) {
        if (FLAG_FILE_PATTERN.matcher(arg).matches()) {
            flagfiles.add(arg);
        } else {
            startupArgs.add(arg);
        }
    }
    if (flagfiles.isEmpty()) {
        throw new UserExecException(String.format(ERROR_MESSAGE_PREFIX + REASON_NO_FLAGFILE, spawn.getMnemonic()));
    }
    if (Iterables.isEmpty(spawn.getToolFiles())) {
        throw new UserExecException(String.format(ERROR_MESSAGE_PREFIX + REASON_NO_TOOLS, spawn.getMnemonic()));
    }
    FileOutErr outErr = actionExecutionContext.getFileOutErr();
    ImmutableList<String> args = ImmutableList.<String>builder().addAll(startupArgs).add("--persistent_worker").addAll(MoreObjects.firstNonNull(extraFlags.get(spawn.getMnemonic()), ImmutableList.<String>of())).build();
    ImmutableMap<String, String> env = spawn.getEnvironment();
    try {
        ActionInputFileCache inputFileCache = actionExecutionContext.getActionInputFileCache();
        HashCode workerFilesHash = WorkerFilesHash.getWorkerFilesHash(spawn.getToolFiles(), actionExecutionContext);
        Map<PathFragment, Path> inputFiles = new SpawnHelpers(execRoot).getMounts(spawn, actionExecutionContext);
        Set<PathFragment> outputFiles = SandboxHelpers.getOutputFiles(spawn);
        WorkerKey key = new WorkerKey(args, env, execRoot, spawn.getMnemonic(), workerFilesHash, inputFiles, outputFiles, writeOutputFiles != null);
        WorkRequest.Builder requestBuilder = WorkRequest.newBuilder();
        for (String flagfile : flagfiles) {
            expandArgument(requestBuilder, flagfile);
        }
        List<ActionInput> inputs = ActionInputHelper.expandArtifacts(spawn.getInputFiles(), actionExecutionContext.getArtifactExpander());
        for (ActionInput input : inputs) {
            byte[] digestBytes = inputFileCache.getDigest(input);
            ByteString digest;
            if (digestBytes == null) {
                digest = ByteString.EMPTY;
            } else {
                digest = ByteString.copyFromUtf8(HashCode.fromBytes(digestBytes).toString());
            }
            requestBuilder.addInputsBuilder().setPath(input.getExecPathString()).setDigest(digest).build();
        }
        WorkResponse response = execInWorker(eventHandler, key, requestBuilder.build(), maxRetries, writeOutputFiles);
        outErr.getErrorStream().write(response.getOutputBytes().toByteArray());
        if (response.getExitCode() != 0) {
            throw new UserExecException(String.format("Worker process sent response with exit code: %d.", response.getExitCode()));
        }
    } catch (IOException e) {
        String message = CommandFailureUtils.describeCommandFailure(verboseFailures, spawn.getArguments(), env, execRoot.getPathString());
        throw new UserExecException(message, e);
    }
}
Also used : FileOutErr(com.google.devtools.build.lib.util.io.FileOutErr) ActionInput(com.google.devtools.build.lib.actions.ActionInput) ByteString(com.google.protobuf.ByteString) ArrayList(java.util.ArrayList) PathFragment(com.google.devtools.build.lib.vfs.PathFragment) EventHandler(com.google.devtools.build.lib.events.EventHandler) ByteString(com.google.protobuf.ByteString) Executor(com.google.devtools.build.lib.actions.Executor) HashCode(com.google.common.hash.HashCode) Path(com.google.devtools.build.lib.vfs.Path) SpawnHelpers(com.google.devtools.build.lib.sandbox.SpawnHelpers) UserExecException(com.google.devtools.build.lib.actions.UserExecException) IOException(java.io.IOException) ActionInputFileCache(com.google.devtools.build.lib.actions.ActionInputFileCache) WorkRequest(com.google.devtools.build.lib.worker.WorkerProtocol.WorkRequest) WorkResponse(com.google.devtools.build.lib.worker.WorkerProtocol.WorkResponse)

Example 13 with Executor

use of com.google.devtools.build.lib.actions.Executor in project bazel by bazelbuild.

the class StandaloneTestStrategy method executeTest.

protected TestResultData executeTest(TestRunnerAction action, Spawn spawn, ActionExecutionContext actionExecutionContext) throws ExecException, InterruptedException, IOException {
    Executor executor = actionExecutionContext.getExecutor();
    Closeable streamed = null;
    Path testLogPath = action.getTestLog().getPath();
    TestResultData.Builder builder = TestResultData.newBuilder();
    long startTime = executor.getClock().currentTimeMillis();
    SpawnActionContext spawnActionContext = executor.getSpawnActionContext(action.getMnemonic());
    try {
        try {
            if (executionOptions.testOutput.equals(TestOutputFormat.STREAMED)) {
                streamed = new StreamedTestOutput(Reporter.outErrForReporter(actionExecutionContext.getExecutor().getEventHandler()), testLogPath);
            }
            spawnActionContext.exec(spawn, actionExecutionContext);
            builder.setTestPassed(true).setStatus(BlazeTestStatus.PASSED).setCachable(true).setPassedLog(testLogPath.getPathString());
        } catch (ExecException e) {
            // Execution failed, which we consider a test failure.
            // TODO(bazel-team): set cachable==true for relevant statuses (failure, but not for
            // timeout, etc.)
            builder.setTestPassed(false).setStatus(e.hasTimedOut() ? BlazeTestStatus.TIMEOUT : BlazeTestStatus.FAILED).addFailedLogs(testLogPath.getPathString());
            if (spawnActionContext.shouldPropagateExecException()) {
                throw e;
            }
        } finally {
            long duration = executor.getClock().currentTimeMillis() - startTime;
            builder.addTestTimes(duration);
            builder.addTestProcessTimes(duration);
            builder.setRunDurationMillis(duration);
            if (streamed != null) {
                streamed.close();
            }
        }
        TestCase details = parseTestResult(action.resolve(actionExecutionContext.getExecutor().getExecRoot()).getXmlOutputPath());
        if (details != null) {
            builder.setTestCase(details);
        }
        if (action.isCoverageMode()) {
            builder.setHasCoverage(true);
        }
        return builder.build();
    } catch (IOException e) {
        throw new TestExecException(e.getMessage());
    }
}
Also used : Path(com.google.devtools.build.lib.vfs.Path) Executor(com.google.devtools.build.lib.actions.Executor) TestResultData(com.google.devtools.build.lib.view.test.TestStatus.TestResultData) TestCase(com.google.devtools.build.lib.view.test.TestStatus.TestCase) Closeable(java.io.Closeable) EnvironmentalExecException(com.google.devtools.build.lib.actions.EnvironmentalExecException) TestExecException(com.google.devtools.build.lib.actions.TestExecException) ExecException(com.google.devtools.build.lib.actions.ExecException) Builder(com.google.devtools.build.lib.view.test.TestStatus.TestResultData.Builder) IOException(java.io.IOException) SpawnActionContext(com.google.devtools.build.lib.actions.SpawnActionContext) TestExecException(com.google.devtools.build.lib.actions.TestExecException)

Example 14 with Executor

use of com.google.devtools.build.lib.actions.Executor in project bazel by bazelbuild.

the class TestStrategy method updateLocalRunfilesDirectory.

/**
   * Ensure the runfiles tree exists and is consistent with the TestAction's manifest
   * ($0.runfiles_manifest), bringing it into consistency if not. The contents of the output file
   * $0.runfiles/MANIFEST, if it exists, are used a proxy for the set of existing symlinks, to avoid
   * the need for recursion.
   */
private static void updateLocalRunfilesDirectory(TestRunnerAction testAction, Path runfilesDir, ActionExecutionContext actionExecutionContext, BinTools binTools, ImmutableMap<String, String> shellEnvironment, boolean enableRunfiles) throws ExecException, InterruptedException {
    Executor executor = actionExecutionContext.getExecutor();
    TestTargetExecutionSettings execSettings = testAction.getExecutionSettings();
    Path outputManifest = runfilesDir.getRelative("MANIFEST");
    try {
        // an up-to-date check.
        if (!outputManifest.isSymbolicLink() && Arrays.equals(outputManifest.getDigest(), execSettings.getInputManifest().getPath().getDigest())) {
            return;
        }
    } catch (IOException e1) {
    // Ignore it - we will just try to create runfiles directory.
    }
    executor.getEventHandler().handle(Event.progress("Building runfiles directory for '" + execSettings.getExecutable().prettyPrint() + "'."));
    new SymlinkTreeHelper(execSettings.getInputManifest().getPath(), runfilesDir, false).createSymlinks(testAction, actionExecutionContext, binTools, shellEnvironment, enableRunfiles);
    executor.getEventHandler().handle(Event.progress(testAction.getProgressMessage()));
}
Also used : TestTargetExecutionSettings(com.google.devtools.build.lib.rules.test.TestTargetExecutionSettings) Path(com.google.devtools.build.lib.vfs.Path) Executor(com.google.devtools.build.lib.actions.Executor) IOException(java.io.IOException)

Example 15 with Executor

use of com.google.devtools.build.lib.actions.Executor in project bazel by bazelbuild.

the class RemoteSpawnStrategy method exec.

/** Executes the given {@code spawn}. */
@Override
public void exec(Spawn spawn, ActionExecutionContext actionExecutionContext) throws ExecException, InterruptedException {
    ActionKey actionKey = null;
    String mnemonic = spawn.getMnemonic();
    Executor executor = actionExecutionContext.getExecutor();
    EventHandler eventHandler = executor.getEventHandler();
    RemoteActionCache actionCache = null;
    RemoteWorkExecutor workExecutor = null;
    if (spawn.isRemotable()) {
        // action to enable server-side parallelism (need a different gRPC channel per action).
        try {
            if (ConcurrentMapFactory.isRemoteCacheOptions(options)) {
                actionCache = new ConcurrentMapActionCache(ConcurrentMapFactory.create(options));
            } else if (GrpcActionCache.isRemoteCacheOptions(options)) {
                actionCache = new GrpcActionCache(options);
            }
            if (actionCache != null && RemoteWorkExecutor.isRemoteExecutionOptions(options)) {
                workExecutor = new RemoteWorkExecutor(options);
            }
        } catch (InvalidConfigurationException e) {
            eventHandler.handle(Event.warn(e.toString()));
        }
    }
    if (!spawn.isRemotable() || actionCache == null) {
        standaloneStrategy.exec(spawn, actionExecutionContext);
        return;
    }
    if (workExecutor == null) {
        execLocally(spawn, actionExecutionContext, actionCache, actionKey);
        return;
    }
    if (executor.reportsSubcommands()) {
        executor.reportSubcommand(spawn);
    }
    executor.getEventBus().post(ActionStatusMessage.runningStrategy(spawn.getResourceOwner(), "remote"));
    try {
        // Temporary hack: the TreeNodeRepository should be created and maintained upstream!
        TreeNodeRepository repository = new TreeNodeRepository(execRoot);
        List<ActionInput> inputs = ActionInputHelper.expandArtifacts(spawn.getInputFiles(), actionExecutionContext.getArtifactExpander());
        TreeNode inputRoot = repository.buildFromActionInputs(inputs);
        repository.computeMerkleDigests(inputRoot);
        Command command = buildCommand(spawn.getArguments(), spawn.getEnvironment());
        Action action = buildAction(spawn.getOutputFiles(), ContentDigests.computeDigest(command), repository.getMerkleDigest(inputRoot));
        // Look up action cache, and reuse the action output if it is found.
        actionKey = ContentDigests.computeActionKey(action);
        ActionResult result = this.options.remoteAcceptCached ? actionCache.getCachedActionResult(actionKey) : null;
        boolean acceptCachedResult = this.options.remoteAcceptCached;
        if (result != null) {
            // just update the TreeNodeRepository and continue the build.
            try {
                actionCache.downloadAllResults(result, execRoot);
                return;
            } catch (CacheNotFoundException e) {
                // Retry the action remotely and invalidate the results.
                acceptCachedResult = false;
            }
        }
        // Upload the command and all the inputs into the remote cache.
        actionCache.uploadBlob(command.toByteArray());
        // TODO(olaola): this should use the ActionInputFileCache for SHA1 digests!
        actionCache.uploadTree(repository, execRoot, inputRoot);
        // TODO(olaola): set BuildInfo and input total bytes as well.
        ExecuteRequest.Builder request = ExecuteRequest.newBuilder().setAction(action).setAcceptCached(acceptCachedResult).setTotalInputFileCount(inputs.size()).setTimeoutMillis(1000 * Spawns.getTimeoutSeconds(spawn, 120));
        // TODO(olaola): set sensible local and remote timouts.
        ExecuteReply reply = workExecutor.executeRemotely(request.build());
        ExecutionStatus status = reply.getStatus();
        result = reply.getResult();
        // action.
        if (status.getSucceeded()) {
            passRemoteOutErr(actionCache, result, actionExecutionContext.getFileOutErr());
            actionCache.downloadAllResults(result, execRoot);
            return;
        }
        if (status.getError() == ExecutionStatus.ErrorCode.EXEC_FAILED || !options.remoteAllowLocalFallback) {
            passRemoteOutErr(actionCache, result, actionExecutionContext.getFileOutErr());
            throw new UserExecException(status.getErrorDetail());
        }
        // For now, we retry locally on all other remote errors.
        // TODO(olaola): add remote retries on cache miss errors.
        execLocally(spawn, actionExecutionContext, actionCache, actionKey);
    } catch (IOException e) {
        throw new UserExecException("Unexpected IO error.", e);
    } catch (InterruptedException e) {
        eventHandler.handle(Event.warn(mnemonic + " remote work interrupted (" + e + ")"));
        Thread.currentThread().interrupt();
        throw e;
    } catch (StatusRuntimeException e) {
        String stackTrace = "";
        if (verboseFailures) {
            stackTrace = "\n" + Throwables.getStackTraceAsString(e);
        }
        eventHandler.handle(Event.warn(mnemonic + " remote work failed (" + e + ")" + stackTrace));
        if (options.remoteAllowLocalFallback) {
            execLocally(spawn, actionExecutionContext, actionCache, actionKey);
        } else {
            throw new UserExecException(e);
        }
    } catch (CacheNotFoundException e) {
        eventHandler.handle(Event.warn(mnemonic + " remote work results cache miss (" + e + ")"));
        if (options.remoteAllowLocalFallback) {
            execLocally(spawn, actionExecutionContext, actionCache, actionKey);
        } else {
            throw new UserExecException(e);
        }
    } catch (UnsupportedOperationException e) {
        eventHandler.handle(Event.warn(mnemonic + " unsupported operation for action cache (" + e + ")"));
    }
}
Also used : Action(com.google.devtools.build.lib.remote.RemoteProtocol.Action) ActionInput(com.google.devtools.build.lib.actions.ActionInput) EventHandler(com.google.devtools.build.lib.events.EventHandler) InvalidConfigurationException(com.google.devtools.build.lib.analysis.config.InvalidConfigurationException) ExecuteRequest(com.google.devtools.build.lib.remote.RemoteProtocol.ExecuteRequest) Executor(com.google.devtools.build.lib.actions.Executor) ExecutionStatus(com.google.devtools.build.lib.remote.RemoteProtocol.ExecutionStatus) TreeNode(com.google.devtools.build.lib.remote.TreeNodeRepository.TreeNode) StatusRuntimeException(io.grpc.StatusRuntimeException) ExecuteReply(com.google.devtools.build.lib.remote.RemoteProtocol.ExecuteReply) UserExecException(com.google.devtools.build.lib.actions.UserExecException) ActionKey(com.google.devtools.build.lib.remote.ContentDigests.ActionKey) IOException(java.io.IOException) ActionResult(com.google.devtools.build.lib.remote.RemoteProtocol.ActionResult) Command(com.google.devtools.build.lib.remote.RemoteProtocol.Command)

Aggregations

Executor (com.google.devtools.build.lib.actions.Executor)26 IOException (java.io.IOException)12 Path (com.google.devtools.build.lib.vfs.Path)10 Artifact (com.google.devtools.build.lib.actions.Artifact)8 ExecException (com.google.devtools.build.lib.actions.ExecException)8 UserExecException (com.google.devtools.build.lib.actions.UserExecException)5 ActionExecutionException (com.google.devtools.build.lib.actions.ActionExecutionException)4 ActionInput (com.google.devtools.build.lib.actions.ActionInput)4 TestExecutorBuilder (com.google.devtools.build.lib.exec.util.TestExecutorBuilder)4 FileOutErr (com.google.devtools.build.lib.util.io.FileOutErr)4 PathFragment (com.google.devtools.build.lib.vfs.PathFragment)4 EventBus (com.google.common.eventbus.EventBus)3 ActionExecutionContext (com.google.devtools.build.lib.actions.ActionExecutionContext)3 ActionExecutionMetadata (com.google.devtools.build.lib.actions.ActionExecutionMetadata)3 ResourceHandle (com.google.devtools.build.lib.actions.ResourceManager.ResourceHandle)3 Spawn (com.google.devtools.build.lib.actions.Spawn)3 ArrayList (java.util.ArrayList)3 HashCode (com.google.common.hash.HashCode)2 ActionInputFileCache (com.google.devtools.build.lib.actions.ActionInputFileCache)2 TreeFileArtifact (com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact)2