static async Task <Possible <List <string> > > launchExternalProcessAndParseOutputAsync(Process process) { var result = new List <string>(); using (var pooledList = Pools.GetStringList()) { var stdErrContent = pooledList.Instance; using (var processExecutor = new AsyncProcessExecutor( process, s_externalProcessTimeout, outputBuilder: line => { if (line != null) { result.Add(line); } }, errorBuilder: line => { if (line != null) { stdErrContent.Add(line); } })) { processExecutor.Start(); await processExecutor.WaitForExitAsync(); await processExecutor.WaitForStdOutAndStdErrAsync(); if (processExecutor.Process.ExitCode != 0) { var stdOut = $"{Environment.NewLine}{string.Join(Environment.NewLine, result)}"; var stdErr = $"{Environment.NewLine}{string.Join(Environment.NewLine, stdErrContent)}"; return(new Failure <string>($"{describeProcess(process)} Process failed with an exit code {processExecutor.Process.ExitCode}{stdOut}{stdErr}")); } if (result.Count == 0) { return(new Failure <string>($"{describeProcess(process)} Parser exited cleanly, but no output was written.")); } if (!int.TryParse(result[0], out var expectedCount)) { var stdOut = $"{Environment.NewLine}{string.Join(Environment.NewLine, result)}"; return(new Failure <string>($"{describeProcess(process)} Failed to parse tool output: {stdOut}")); } if (expectedCount != result.Count - 1) { var stdOut = $"{Environment.NewLine}{string.Join(Environment.NewLine, result)}"; return(new Failure <string>($"{describeProcess(process)} Output line count does not match the expected count: {stdOut}")); } result.RemoveAt(0); return(result); } } }
private async Task InitVmAsync() { // (1) Create and serialize 'StartBuild' request. string startBuildRequestPath = Path.GetTempFileName(); using (var password = LowPrivilegeAccountUtils.GetLowPrivilegeBuildPassword()) { //This will be temporary, will fix the problem exposing the password var startBuildRequest = new StartBuildRequest { HostLowPrivilegeUsername = LowPrivilegeAccountUtils.GetLowPrivilegeBuildAccount(), HostLowPrivilegePassword = LowPrivilegeAccountUtils.GetUnsecuredString(password) }; VmSerializer.SerializeToFile(startBuildRequestPath, startBuildRequest); } // (2) Create a process to execute VmCommandProxy. string arguments = $"{VmCommand.StartBuild} /{VmCommand.Param.InputJsonFile}:\"{startBuildRequestPath}\""; var process = CreateVmCommandProxyProcess(arguments, Path.GetDirectoryName(startBuildRequestPath)); var stdOutForStartBuild = new StringBuilder(); var stdErrForStartBuild = new StringBuilder(); // (3) Run VmCommandProxy to start build. using (var executor = new AsyncProcessExecutor( process, TimeSpan.FromMilliseconds(-1), line => { if (line != null) { stdOutForStartBuild.AppendLine(line); } }, line => { if (line != null) { stdErrForStartBuild.AppendLine(line); } })) { executor.Start(); await executor.WaitForExitAsync(); await executor.WaitForStdOutAndStdErrAsync(); if (executor.Process.ExitCode != 0) { string stdOut = $"{Environment.NewLine}StdOut:{Environment.NewLine}{stdOutForStartBuild.ToString()}"; string stdErr = $"{Environment.NewLine}StdErr:{Environment.NewLine}{stdErrForStartBuild.ToString()}"; throw new BuildXLException($"Failed to init VM '{VmCommandProxy} {arguments}', with exit code {executor.Process.ExitCode}{stdOut}{stdErr}"); } } }
/// <summary> /// Executes a Process /// </summary> /// <param name="exePath">Path to exe file</param> /// <param name="args">Args to be passed to exe</param> /// <param name="tempDir">Working directory for exe</param> /// <returns>(<see cref="Process.ExitCode"/> == 0 AND !timeOut, StdErr, StdOut)</returns> private async static Task <Possible <bool> > TryExecuteProcessAsync(string exePath, string args, string tempDir) { var process = new Process { StartInfo = new ProcessStartInfo(exePath, args) { CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, WorkingDirectory = tempDir }, EnableRaisingEvents = true }; StringBuilder stdOutBuilder = new StringBuilder(); StringBuilder stdErrBuilder = new StringBuilder(); using (var executor = new AsyncProcessExecutor( process, TimeSpan.FromMinutes(ExecutableMaxRuntimeInMinute), line => { if (line != null) { stdOutBuilder.AppendLine(line); } }, line => { if (line != null) { stdErrBuilder.AppendLine(line); } })) { executor.Start(); await executor.WaitForExitAsync(); await executor.WaitForStdOutAndStdErrAsync(); if (executor.Process.ExitCode == 0 && !executor.TimedOut) { return(true); } string errorReturn = $"StdErr: { stdErrBuilder }, StdOut: { stdOutBuilder }"; return(new Failure <string>(errorReturn)); } }
private async Task InitVmAsync() { // (1) Create a process to execute VmCommandProxy. string arguments = $"{VmCommands.InitializeVm}"; var process = CreateVmCommandProxyProcess(arguments, Path.GetDirectoryName(Path.GetTempFileName())); m_logStartInit?.Invoke($"{VmCommandProxy} {arguments}"); var stdOutForStartBuild = new StringBuilder(); var stdErrForStartBuild = new StringBuilder(); string provenance = $"[{nameof(VmInitializer)}]"; // (2) Run VmCommandProxy to start build. using (var executor = new AsyncProcessExecutor( process, TimeSpan.FromMinutes(InitVmTimeoutInMinute), line => { if (line != null) { stdOutForStartBuild.AppendLine(line); } }, line => { if (line != null) { stdErrForStartBuild.AppendLine(line); } }, provenance: provenance, logger: message => m_logInitExecution?.Invoke(message))) { executor.Start(); await executor.WaitForExitAsync(); await executor.WaitForStdOutAndStdErrAsync(); string stdOut = $"{Environment.NewLine}StdOut:{Environment.NewLine}{stdOutForStartBuild.ToString()}"; string stdErr = $"{Environment.NewLine}StdErr:{Environment.NewLine}{stdErrForStartBuild.ToString()}"; if (executor.Process.ExitCode != 0) { throw new BuildXLException($"Failed to init VM '{VmCommandProxy} {arguments}', with exit code {executor.Process.ExitCode}{stdOut}{stdErr}"); } m_logEndInit?.Invoke($"Exit code {executor.Process.ExitCode}{stdOut}{stdErr}"); } }