add tcp keep alive hack to net5 target (#560)

* add tcp keep alive hack to net5 target

* remove unused code

* fix ep

* Update buildtest.yaml

* fix netstandard21

* fix space

* fix net5 warning

* more comment
This commit is contained in:
Boshi Lian
2021-03-11 09:32:22 -08:00
committed by GitHub
parent d48e93c1f6
commit 655a42c6bd
8 changed files with 53 additions and 11 deletions

View File

@@ -4,6 +4,8 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using k8s.Exceptions;
using k8s.Models;
@@ -166,6 +168,39 @@ namespace k8s
private void CreateHttpClient(DelegatingHandler[] handlers)
{
FirstMessageHandler = HttpClientHandler = CreateRootHandler();
#if NET5_0
// https://github.com/kubernetes-client/csharp/issues/533
// net5 only
// this is a temp fix to attach SocketsHttpHandler to HttpClient in order to set SO_KEEPALIVE
// https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/
//
// _underlyingHandler is not a public accessible field
// src of net5 HttpClientHandler and _underlyingHandler field defined here
// https://github.com/dotnet/runtime/blob/79ae74f5ca5c8a6fe3a48935e85bd7374959c570/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs#L22
//
// Should remove after better solution
var sh = new SocketsHttpHandler();
sh.ConnectCallback = async (context, token) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp)
{
NoDelay = true,
};
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
await socket.ConnectAsync(context.DnsEndPoint.Host, context.DnsEndPoint.Port, token).ConfigureAwait(false);
return new NetworkStream(socket, ownsSocket: true);
};
var p = HttpClientHandler.GetType().GetField("_underlyingHandler", BindingFlags.NonPublic | BindingFlags.Instance);
p.SetValue(HttpClientHandler, (sh));
#endif
if (handlers == null || handlers.Length == 0)
{
// ensure we have at least one DelegatingHandler so AppendDelegatingHandler will work

View File

@@ -151,7 +151,11 @@ namespace k8s
httpResponse.StatusCode));
if (httpResponse.Content != null)
{
#if NET5_0
responseContent = await httpResponse.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
#else
responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
#endif
}
ex.Request = new HttpRequestMessageWrapper(httpRequest, responseContent);

View File

@@ -319,7 +319,7 @@ namespace k8s
}
#endif
#if NETSTANDARD2_1
#if NETSTANDARD2_1 || NET5_0
if (this.CaCerts != null)
{
webSocketBuilder.ExpectServerCertificate(this.CaCerts);
@@ -334,7 +334,7 @@ namespace k8s
{
webSocketBuilder.Options.AddSubProtocol(webSocketSubProtocol);
}
#endif // NETSTANDARD2_1
#endif // NETSTANDARD2_1 || NET5_0
// Send Request
cancellationToken.ThrowIfCancellationRequested();
@@ -366,8 +366,11 @@ namespace k8s
}
else
{
#if NET5_0
var content = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
#else
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
#endif
// Try to parse the content as a V1Status object
var genericObject = SafeJsonConvert.DeserializeObject<KubernetesObject>(content);
V1Status status = null;

View File

@@ -9,7 +9,7 @@
<PackageIconUrl>https://raw.githubusercontent.com/kubernetes/kubernetes/master/logo/logo.png</PackageIconUrl>
<PackageTags>kubernetes;docker;containers;</PackageTags>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>netstandard2.0;netstandard2.1;net5</TargetFrameworks>
<RootNamespace>k8s</RootNamespace>
<SignAssembly>true</SignAssembly>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@@ -50,7 +50,7 @@ namespace k8s
}
#endif
#if NETSTANDARD2_1
#if NETSTANDARD2_1 || NET5_0
public WebSocketBuilder ExpectServerCertificate(X509Certificate2Collection serverCertificate)
{
Options.RemoteCertificateValidationCallback
@@ -70,7 +70,7 @@ namespace k8s
return this;
}
#endif // NETSTANDARD2_1
#endif // NETSTANDARD2_1 || NET5_0
public virtual async Task<WebSocket> BuildAndConnectAsync(Uri uri, CancellationToken cancellationToken)
{

View File

@@ -165,7 +165,7 @@ namespace k8s.Tests
}
}
#if NETSTANDARD2_1 // The functionality under test, here, is dependent on managed HTTP / WebSocket in .NET Core 2.1 or newer.
#if NETSTANDARD2_1 || NET5_0 // The functionality under test, here, is dependent on managed HTTP / WebSocket in .NET Core 2.1 or newer.
// this test doesn't work on OSX and is inconsistent on windows
[OperatingSystemDependentFact(Exclude = OperatingSystems.OSX | OperatingSystems.Windows)]
public void Cert()
@@ -338,7 +338,7 @@ namespace k8s.Tests
}
}
}
#endif // NETSTANDARD2_1
#endif // NETSTANDARD2_1 || NET5_0
[Fact]
public void ExternalToken()

View File

@@ -1,4 +1,4 @@
#if !NETSTANDARD2_1
#if !NETSTANDARD2_1 || NET5_0
/*
* These tests are only for the netstandard version of the client (there are separate tests for netcoreapp that connect to a local test-hosted server).
*/

View File

@@ -1,4 +1,4 @@
#if !NETSTANDARD2_1
#if !NETSTANDARD2_1 || NET5_0
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -43,4 +43,4 @@ namespace k8s.Tests.Mock
}
}
#endif // !NETSTANDARD2_1
#endif // !NETSTANDARD2_1 || NET5_0