public async Task NamespacedPodExecAsyncHttpExceptionWithStatus() { var kubernetesMock = new Moq.Mock <Kubernetes>( new object[] { Moq.Mock.Of <ServiceClientCredentials>(), new DelegatingHandler[] { } }); var command = new string[] { "/bin/bash", "-c", "echo Hello, World!" }; var handler = new ExecAsyncCallback((stdIn, stdOut, stdError) => Task.CompletedTask); var status = new V1Status(); kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) .Throws(new HttpOperationException() { Body = status }); using (Kubernetes client = kubernetesMock.Object) { var ex = await Assert.ThrowsAsync <KubernetesException>(() => client.NamespacedPodExecAsync( "pod-name", "pod-namespace", "my-container", command, false, handler, CancellationToken.None)) .ConfigureAwait(false); Assert.Same(status, ex.Status); } }
public async Task NamespacedPodExecAsyncGenericException() { var kubernetesMock = new Moq.Mock <Kubernetes>( new object[] { new KubernetesClientConfiguration() { Host = "http://localhost" }, new DelegatingHandler[] { } }) { CallBase = true }; var command = new string[] { "/bin/bash", "-c", "echo Hello, World!" }; var handler = new ExecAsyncCallback((stdIn, stdOut, stdError) => Task.CompletedTask); var exception = new Exception(); kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) .Throws(exception); using (Kubernetes client = kubernetesMock.Object) { var ex = await Assert.ThrowsAsync <Exception>(() => client.NamespacedPodExecAsync( "pod-name", "pod-namespace", "my-container", command, false, handler, CancellationToken.None)) .ConfigureAwait(false); Assert.Same(exception, ex); } }
public async Task NamespacedPodExecAsyncExitCodeNonZero() { var processStatus = new V1Status() { Metadata = null, Status = "Failure", Message = "command terminated with non-zero exit code: Error executing in Docker Container: 1", Reason = "NonZeroExitCode", Details = new V1StatusDetails() { Causes = new List <V1StatusCause>() { new V1StatusCause() { Reason = "ExitCode", Message = "1" }, }, }, }; var processStatusJson = JsonSerializer.SerializeToUtf8Bytes(processStatus); var handler = new ExecAsyncCallback((stdIn, stdOut, stdError) => Task.CompletedTask); using (MemoryStream stdIn = new MemoryStream()) using (MemoryStream stdOut = new MemoryStream()) using (MemoryStream stdErr = new MemoryStream()) using (MemoryStream errorStream = new MemoryStream(processStatusJson)) { var muxedStream = new Moq.Mock <IStreamDemuxer>(); muxedStream.Setup(m => m.GetStream(null, ChannelIndex.StdIn)).Returns(stdIn); muxedStream.Setup(m => m.GetStream(ChannelIndex.StdOut, null)).Returns(stdOut); muxedStream.Setup(m => m.GetStream(ChannelIndex.StdErr, null)).Returns(stdErr); muxedStream.Setup(m => m.GetStream(ChannelIndex.Error, null)).Returns(errorStream); var kubernetesMock = new Moq.Mock <Kubernetes>( new object[] { new KubernetesClientConfiguration() { Host = "http://localhost" }, new DelegatingHandler[] { } }) { CallBase = true }; var command = new string[] { "/bin/bash", "-c", "echo Hello, World!" }; var exception = new Exception(); kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) .Returns(Task.FromResult(muxedStream.Object)); using (Kubernetes client = kubernetesMock.Object) { var exitCode = await client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", command, false, handler, CancellationToken.None).ConfigureAwait(false); Assert.Equal(1, exitCode); } } }
/// <summary> /// Helper method for running node commands via a busybox container. /// </summary> /// <param name="podName"></param> /// <param name="namespace"></param> /// <param name="command"></param> /// <param name="containerName"></param> /// <param name="retry"></param> /// <returns>The command output as lines of text.</returns> public async Task <string> ExecInPodAsync( string podName, string @namespace, string command, string containerName = null, bool retry = false) { var podCommand = new string[] { "chroot", "/host", "/bin/bash", "-c", command }; var pod = await k8s.ReadNamespacedPodAsync(podName, @namespace); if (string.IsNullOrEmpty(containerName)) { containerName = pod.Spec.Containers.FirstOrDefault().Name; } string stdOut = ""; string stdErr = ""; var handler = new ExecAsyncCallback(async(_stdIn, _stdOut, _stdError) => { stdOut = Encoding.UTF8.GetString(await _stdOut.ReadToEndAsync()); stdErr = Encoding.UTF8.GetString(await _stdError.ReadToEndAsync()); }); var exitcode = await k8s.NamespacedPodExecAsync(podName, @namespace, containerName, podCommand, true, handler, CancellationToken.None); if (exitcode != 0) { throw new KubernetesException($@"{stdOut} {stdErr}"); } var result = new StringBuilder(); foreach (var line in stdOut.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)) { result.AppendLine(line); } return(result.ToString()); }
public async Task <int> NamespacedPodExecAsync(string name, string @namespace, string container, IEnumerable <string> 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 this.MuxedStreamNamespacedPodExecAsync( name: name, @namespace: @namespace, command: command, container: container, tty: tty, cancellationToken: cancellationToken).ConfigureAwait(false)) using (Stream stdIn = muxedStream.GetStream(null, ChannelIndex.StdIn)) using (Stream stdOut = muxedStream.GetStream(ChannelIndex.StdOut, null)) using (Stream stdErr = muxedStream.GetStream(ChannelIndex.StdErr, null)) using (Stream error = muxedStream.GetStream(ChannelIndex.Error, null)) using (StreamReader 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 <V1Status>(errors); return(GetExitCodeOrThrow(returnMessage)); } } catch (HttpOperationException httpEx) when(httpEx.Body is V1Status) { throw new KubernetesException((V1Status)httpEx.Body); } }