using k8s.Models; using Microsoft.Rest; using Microsoft.Rest.Serialization; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace k8s { public partial class Kubernetes { public async Task NamespacedPodExecAsync(string name, string @namespace, string container, IEnumerable command, bool tty, ExecAsyncCallback action, CancellationToken cancellationToken) { // All other parameters are being validated by MuxedStreamNamespacedPodExecAsync if (action == null) { throw new ArgumentNullException(nameof(action)); } try { using (var muxedStream = await MuxedStreamNamespacedPodExecAsync( name, @namespace, command, container, tty: tty, cancellationToken: cancellationToken).ConfigureAwait(false)) using (var stdIn = muxedStream.GetStream(null, ChannelIndex.StdIn)) using (var stdOut = muxedStream.GetStream(ChannelIndex.StdOut, null)) using (var stdErr = muxedStream.GetStream(ChannelIndex.StdErr, null)) using (var error = muxedStream.GetStream(ChannelIndex.Error, null)) using (var errorReader = new StreamReader(error)) { muxedStream.Start(); await action(stdIn, stdOut, stdErr).ConfigureAwait(false); var errors = await errorReader.ReadToEndAsync().ConfigureAwait(false); // StatusError is defined here: // https://github.com/kubernetes/kubernetes/blob/068e1642f63a1a8c48c16c18510e8854a4f4e7c5/staging/src/k8s.io/apimachinery/pkg/api/errors/errors.go#L37 var returnMessage = SafeJsonConvert.DeserializeObject(errors); return GetExitCodeOrThrow(returnMessage); } } catch (HttpOperationException httpEx) when (httpEx.Body is V1Status) { throw new KubernetesException((V1Status)httpEx.Body, httpEx); } } /// /// Determines the process' exit code based on a message. /// /// This will: /// - return 0 if the process completed successfully /// - return the exit code if the process completed with a non-zero exit code /// - throw a in all other cases. /// /// /// A object. /// /// /// The process exit code. /// public static int GetExitCodeOrThrow(V1Status status) { if (status == null) { throw new ArgumentNullException(nameof(status)); } if (status.Status == "Success") { return 0; } else if (status.Status == "Failure" && status.Reason == "NonZeroExitCode") { var exitCodeString = status.Details.Causes.FirstOrDefault(c => c.Reason == "ExitCode")?.Message; if (int.TryParse(exitCodeString, out var exitCode)) { return exitCode; } else { throw new KubernetesException(status); } } else { throw new KubernetesException(status); } } } }