public int RunLongRunningCommand()

in src/common/Kubernetes/KubectlImpl.cs [224:342]


        public int RunLongRunningCommand(
            KubernetesCommandName commandName,
            string command,
            Action<string> onStdOut,
            Action<string> onStdErr,
            CancellationToken cancellationToken,
            Dictionary<string, string> envVariables = null,
            bool log137ExitCodeErrorAsWarning = false)
        {
            Debug.Assert(cancellationToken != default(CancellationToken), "CancellationToken cannot be passed as default for long running operations");
            _log.Info("Invoking kubectl {0} command: {1}", commandName.ToString(), new PII(command));
            Stopwatch w = new Stopwatch();
            var stdOutBuilder = new FixedSizeStringBuilder(MaxBufferSize);
            var stdErrBuilder = new FixedSizeStringBuilder(MaxBufferSize);

            var kubectlProcess = _platform.CreateProcess(
                new ProcessStartInfo()
                {
                    FileName = GetKubectlFilepath(),
                    Arguments = command,
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    CreateNoWindow = true
                });

            if (envVariables != null)
            {
                foreach (KeyValuePair<string, string> env in envVariables)
                {
                    kubectlProcess.StartInfo.EnvironmentVariables[env.Key] = env.Value;
                }
            }
            try
            {
                Action killKubectlProcess =
                    () =>
                    {
                        try
                        {
                            if (!kubectlProcess.HasExited)
                            {
                                kubectlProcess.Kill();
                                kubectlProcess.Dispose();
                            }
                        }
                        catch (Exception e)
                        {
                            _log.Exception(e);
                        }
                    };

                kubectlProcess.OutputDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        stdOutBuilder.AppendLine(e.Data);
                        onStdOut?.Invoke(e.Data);
                    }
                };

                kubectlProcess.ErrorDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                    {
                        stdErrBuilder.AppendLine(e.Data);
                        onStdErr?.Invoke(e.Data);
                    }
                };
                w.Start();
                kubectlProcess.Start();
                using (cancellationToken.Register(killKubectlProcess))
                {
                    kubectlProcess.BeginOutputReadLine();
                    kubectlProcess.BeginErrorReadLine();

                    _log.Info("Invoked long running kubectl {0} command: '{1}'", commandName.ToString(), new PII(command));
                    if (stdErrBuilder.Length > 0)
                    {
                        LogFailure(commandName, command, -1, stdOutBuilder, stdErrBuilder, log137ExitCodeErrorAsWarning);
                    }

                    kubectlProcess.WaitForExit();
                }

                return 0;
            }
            catch (Exception e)
            {
                if (e is KubectlException)
                {
                    _log.ExceptionAsWarning(e);
                }
                else
                {
                    _log.Exception(e);
                }

                _log.Error("kubectl {0} command: '{1}' failed with exception {2}", commandName.ToString(), new PII(command), e.Message);
                // Killing and disposing failed process
                if (!kubectlProcess.HasExited)
                {
                    // Try and catch exceptions in case of race conditions or other unexpected errors killing the process
                    try
                    {
                        kubectlProcess.Kill();
                    }
                    catch (Exception kubeEx)
                    {
                        _log.Warning("Failed to kill kubectl {0}", kubeEx.Message);
                    }
                }
                throw;
            }
            finally
            {
                kubectlProcess.Dispose();
            }
        }