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();
}
}