in src/common/Kubernetes/KubernetesClient.cs [888:988]
private int InvokeKubectlCommand(
KubernetesCommandName commandName,
string command,
bool shortRunningOperation,
int? timeoutMs,
Action<string> onStdOut = null,
Action<string> onStdErr = null,
bool logOutput = false,
bool shouldIgnoreErrors = false,
CancellationToken cancellationToken = default(CancellationToken))
{
if (shortRunningOperation && timeoutMs == null)
{
throw new InvalidUsageException(this._log.OperationContext, "Short running kubectl command is being invoked without passing 'timeoutMs' parameter.");
}
string tempKubeconfigFile = _fileSystem.Path.GetTempFilePath();
try
{
string arguments = command;
if (_k8SConfiguration != null)
{
// We do not have a kubeconfig file, that is needed for kubectl, so we create a temp one and point kubectl to it
var contents = KubernetesYaml.Serialize(_k8SConfiguration);
if (!string.IsNullOrEmpty(contents))
{
_fileSystem.WriteAllTextToFile(tempKubeconfigFile, contents);
arguments = $"--kubeconfig=\"{tempKubeconfigFile}\" {arguments}";
}
}
else if (!string.IsNullOrEmpty(_activeKubeConfigFilePath))
{
// We do have a kubeconfig file, we should use that one.
// NOTE: this is especially relevant for when the kubectl command modifies the kubeconfig (e.g. when logging in with AAD to run a kubectl command)
arguments = $"--kubeconfig=\"{_activeKubeConfigFilePath}\" {arguments}";
}
var commandLogProperties = new Dictionary<string, object>();
var outputBuilder = new StringBuilder();
Action<string> stdOutHandler = output =>
{
if (logOutput)
{
outputBuilder.AppendLine(output);
}
onStdOut?.Invoke(output);
};
Action<string> stdErrHandler = error =>
{
commandLogProperties[Property.Error] = error;
onStdErr?.Invoke(error);
};
int exitCode;
if (shortRunningOperation)
{
exitCode = RunShortRunningCommand(
commandName,
arguments,
stdOutHandler,
stdErrHandler,
cancellationToken,
log137ExitCodeErrorAsWarning: shouldIgnoreErrors,
timeoutMs: timeoutMs.Value);
}
else
{
exitCode = RunLongRunningCommand(
commandName,
arguments,
stdOutHandler,
stdErrHandler,
cancellationToken,
log137ExitCodeErrorAsWarning: shouldIgnoreErrors);
}
commandLogProperties[Property.ExitCode] = exitCode;
var success = shortRunningOperation ? exitCode == 0
: (cancellationToken.IsCancellationRequested || exitCode == 0);
if (logOutput)
{
commandLogProperties[Property.Output] = new PII(outputBuilder.ToString());
}
// If shouldIgnoreErrors is set to true, this failure is expected in that case. Marking it as success.
this._log.Dependency(Dependency.Kubernetes, Enum.GetName(typeof(KubernetesCommandName), commandName), success: success || shouldIgnoreErrors, properties: commandLogProperties);
return exitCode;
}
finally
{
if (!string.IsNullOrEmpty(tempKubeconfigFile) && _fileSystem.FileExists(tempKubeconfigFile))
{
_fileSystem.DeleteFile(tempKubeconfigFile);
}
}
}