From f3f1f03784b1995e9233436cb563270e3f3bff21 Mon Sep 17 00:00:00 2001 From: Avinesh Singh Date: Sat, 18 Nov 2023 20:39:23 +0530 Subject: [PATCH 1/3] Fix: Exec Process deadlock WaitForExit should have been called after all other methods are called on the process --- .../KubernetesClientConfiguration.ConfigFile.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs index e74660bc9..8a6b45dc6 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs @@ -537,12 +537,13 @@ public static ExecCredentialResponse ExecuteExternalCommand(ExternalExecution co try { - if (!process.WaitForExit((int)(ExecTimeout.TotalMilliseconds))) + var responseObject = KubernetesJson.Deserialize(process.StandardOutput.ReadToEnd()); + + if (!process.WaitForExit((int)ExecTimeout.TotalMilliseconds)) { throw new KubeConfigException("external exec failed due to timeout"); } - var responseObject = KubernetesJson.Deserialize(process.StandardOutput.ReadToEnd()); if (responseObject == null || responseObject.ApiVersion != config.ApiVersion) { throw new KubeConfigException( From 0380f953790288c76d248ce20996fc3a71b2a371 Mon Sep 17 00:00:00 2001 From: Avinesh Singh Date: Mon, 20 Nov 2023 20:46:40 +0530 Subject: [PATCH 2/3] Non-blocking standard output stream parsing --- ...ubernetesClientConfiguration.ConfigFile.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs index 8a6b45dc6..242c73623 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs @@ -5,6 +5,7 @@ using System.Net; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; +using System.Text; namespace k8s { @@ -537,13 +538,23 @@ public static ExecCredentialResponse ExecuteExternalCommand(ExternalExecution co try { - var responseObject = KubernetesJson.Deserialize(process.StandardOutput.ReadToEnd()); + var output = new StringBuilder(); + process.OutputDataReceived += (_, args) => + { + if (args.Data != null) + { + output.Append(args.Data); + } + }; + process.BeginOutputReadLine(); if (!process.WaitForExit((int)ExecTimeout.TotalMilliseconds)) { throw new KubeConfigException("external exec failed due to timeout"); } + var responseObject = KubernetesJson.Deserialize(output.ToString()); + if (responseObject == null || responseObject.ApiVersion != config.ApiVersion) { throw new KubeConfigException( @@ -554,10 +565,8 @@ public static ExecCredentialResponse ExecuteExternalCommand(ExternalExecution co { return responseObject; } - else - { - throw new KubeConfigException($"external exec failed missing token or clientCertificateData field in plugin output"); - } + + throw new KubeConfigException($"external exec failed missing token or clientCertificateData field in plugin output"); } catch (JsonException ex) { From 6000c7b87f2383c37953cd2f57d57ff9e458445f Mon Sep 17 00:00:00 2001 From: Avinesh Singh Date: Wed, 29 Nov 2023 01:24:24 +0530 Subject: [PATCH 3/3] Force buffer flush for non-infinite timeout --- .../KubernetesClientConfiguration.ConfigFile.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs index 242c73623..ed5112296 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs @@ -553,6 +553,12 @@ public static ExecCredentialResponse ExecuteExternalCommand(ExternalExecution co throw new KubeConfigException("external exec failed due to timeout"); } + // Force flush the output buffer to avoid case of missing data + if (ExecTimeout != Timeout.InfiniteTimeSpan) + { + process.WaitForExit(); + } + var responseObject = KubernetesJson.Deserialize(output.ToString()); if (responseObject == null || responseObject.ApiVersion != config.ApiVersion)