Kubernetes.Classic: add support for netstandard2.0 and net48 (#808)
* support gh nuget (#11) * trim to fit net48 * add net48 support * add very test framework * add test body * Revert "support gh nuget (#11)" This reverts commit 5cdaf59690170be44e4554485fb2e89785a6a1cf.
This commit is contained in:
@@ -51,7 +51,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "yaml", "examples\yaml\yaml.
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Models", "src\KubernetesClient.Models\KubernetesClient.Models.csproj", "{F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesClient.Basic", "src\KubernetesClient.Basic\KubernetesClient.Basic.csproj", "{927995F5-05CC-4078-8805-8E6CC06914D8}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Basic", "src\KubernetesClient.Basic\KubernetesClient.Basic.csproj", "{927995F5-05CC-4078-8805-8E6CC06914D8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Classic", "src\KubernetesClient.Classic\KubernetesClient.Classic.csproj", "{80F19E8A-F097-4AA4-A68C-D417B96BBC68}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesClient.Classic.Tests", "tests\KubernetesClient.Classic.Tests\KubernetesClient.Classic.Tests.csproj", "{FD90C861-56C6-4536-B7F5-AC7779296384}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csrApproval", "examples\csrApproval\csrApproval.csproj", "{F626860C-F141-45B3-9DDD-88AD3932ACAF}"
|
||||
EndProject
|
||||
@@ -329,6 +333,30 @@ Global
|
||||
{927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x64.Build.0 = Release|Any CPU
|
||||
{927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x86.Build.0 = Release|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x64.Build.0 = Release|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x86.Build.0 = Release|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x86.Build.0 = Release|Any CPU
|
||||
{F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@@ -368,6 +396,8 @@ Global
|
||||
{17AB0AD8-6C90-42DD-880C-16B5AC4A373F} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
|
||||
{F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
|
||||
{927995F5-05CC-4078-8805-8E6CC06914D8} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
|
||||
{80F19E8A-F097-4AA4-A68C-D417B96BBC68} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
|
||||
{FD90C861-56C6-4536-B7F5-AC7779296384} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
|
||||
{F626860C-F141-45B3-9DDD-88AD3932ACAF} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
|
||||
4
src/KubernetesClient.Classic/Global.cs
Normal file
4
src/KubernetesClient.Classic/Global.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
global using System;
|
||||
global using System.Collections.Generic;
|
||||
global using System.Linq;
|
||||
global using System.Text.Json;
|
||||
43
src/KubernetesClient.Classic/KubernetesClient.Classic.csproj
Normal file
43
src/KubernetesClient.Classic/KubernetesClient.Classic.csproj
Normal file
@@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net48</TargetFrameworks>
|
||||
<RootNamespace>k8s</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
|
||||
<PackageReference Include="System.IO.Abstractions" Version="13.2.47" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.13.1" />
|
||||
<PackageReference Include="IdentityModel.OidcClient" Version="4.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\KubernetesClient.Models\KubernetesClient.Models.csproj" />
|
||||
<ProjectReference Include="..\KubernetesClient.Basic\KubernetesClient.Basic.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\KubernetesClient\CertUtils.cs" />
|
||||
<Compile Include="..\KubernetesClient\FileUtils.cs" />
|
||||
<Compile Include="..\KubernetesClient\IKubernetes.cs" />
|
||||
<Compile Include="..\KubernetesClient\Kubernetes.ConfigInit.cs" />
|
||||
<Compile Include="..\KubernetesClient\Kubernetes.cs" />
|
||||
<Compile Include="..\KubernetesClient\KubernetesClientConfiguration.ConfigFile.cs" />
|
||||
<Compile Include="..\KubernetesClient\KubernetesClientConfiguration.InCluster.cs" />
|
||||
<Compile Include="..\KubernetesClient\KubernetesClientConfiguration.cs" />
|
||||
<Compile Include="..\KubernetesClient\KubernetesException.cs" />
|
||||
|
||||
<Compile Include="..\KubernetesClient\Exceptions\KubeConfigException.cs" />
|
||||
<Compile Include="..\KubernetesClient\Exceptions\KubernetesClientException.cs" />
|
||||
|
||||
<Compile Include="..\KubernetesClient\Authentication\ExecTokenProvider.cs" />
|
||||
<Compile Include="..\KubernetesClient\Authentication\GcpTokenProvider.cs" />
|
||||
<Compile Include="..\KubernetesClient\Authentication\OidcTokenProvider.cs" />
|
||||
<Compile Include="..\KubernetesClient\Authentication\TokenFileAuth.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Net.Http" Condition="'$(TargetFramework)' == 'net48'" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -17,13 +17,21 @@ namespace k8s.Authentication
|
||||
TokenFile = tokenFile;
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_1_OR_GREATER
|
||||
public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
|
||||
#else
|
||||
public Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
|
||||
#endif
|
||||
{
|
||||
if (TokenExpiresAt < DateTime.UtcNow)
|
||||
{
|
||||
#if NETSTANDARD2_1_OR_GREATER
|
||||
token = await File.ReadAllTextAsync(TokenFile, cancellationToken)
|
||||
.ContinueWith(r => r.Result.Trim(), cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
#else
|
||||
token = File.ReadAllText(TokenFile).Trim();
|
||||
#endif
|
||||
// in fact, the token has a expiry of 10 minutes and kubelet
|
||||
// refreshes it at 8 minutes of its lifetime. setting the expiry
|
||||
// of 1 minute makes sure the token is reloaded regularly so
|
||||
@@ -32,8 +40,11 @@ namespace k8s.Authentication
|
||||
// < 10-8-1 minute.
|
||||
TokenExpiresAt = DateTime.UtcNow.AddMinutes(1);
|
||||
}
|
||||
|
||||
#if NETSTANDARD2_1_OR_GREATER
|
||||
return new AuthenticationHeaderValue("Bearer", token);
|
||||
#else
|
||||
return Task.FromResult(new AuthenticationHeaderValue("Bearer", token));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ namespace k8s
|
||||
Initialize();
|
||||
ValidateConfig(config);
|
||||
CaCerts = config.SslCaCerts;
|
||||
#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
|
||||
SkipTlsVerify = config.SkipTlsVerify;
|
||||
#endif
|
||||
CreateHttpClient(handlers, config);
|
||||
InitializeFromConfig(config);
|
||||
HttpClientTimeout = config.HttpClientTimeout;
|
||||
@@ -100,9 +102,11 @@ namespace k8s
|
||||
|
||||
private X509Certificate2Collection CaCerts { get; }
|
||||
|
||||
#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
|
||||
private X509Certificate2 ClientCert { get; }
|
||||
|
||||
private bool SkipTlsVerify { get; }
|
||||
#endif
|
||||
|
||||
// NOTE: this method replicates the logic that the base ServiceClient uses except that it doesn't insert the RetryDelegatingHandler
|
||||
// and it does insert the WatcherDelegatingHandler. we don't want the RetryDelegatingHandler because it has a very broad definition
|
||||
|
||||
@@ -71,7 +71,11 @@ namespace k8s
|
||||
|
||||
if (watch == true)
|
||||
{
|
||||
#if NETSTANDARD2_0 || NET48
|
||||
throw new KubernetesException("watch not supported");
|
||||
#else
|
||||
httpResponse.Content = new LineSeparatedHttpContent(httpResponse.Content, cancellationToken);
|
||||
#endif
|
||||
}
|
||||
|
||||
try
|
||||
@@ -100,7 +104,9 @@ namespace k8s
|
||||
var httpRequest = new HttpRequestMessage();
|
||||
httpRequest.Method = new HttpMethod(method);
|
||||
httpRequest.RequestUri = new Uri(BaseUri, relativeUri);
|
||||
#if NETSTANDARD2_1_OR_GREATER
|
||||
httpRequest.Version = HttpVersion.Version20;
|
||||
#endif
|
||||
// Set Headers
|
||||
if (customHeaders != null)
|
||||
{
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
<ProjectReference Include="KubernetesClient.Models/KubernetesClient.Models.csproj" />
|
||||
<ProjectReference Include="KubernetesClient.Basic/KubernetesClient.Basic.csproj" />
|
||||
<ProjectReference Include="KubernetesClient/KubernetesClient.csproj" />
|
||||
<ProjectReference Include="KubernetesClient.Classic/KubernetesClient.Classic.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<IsPackable>false</IsPackable>
|
||||
<RootNamespace>k8s.Tests</RootNamespace>
|
||||
<TargetFramework Condition="'$(OS)' != 'Windows_NT'">net6</TargetFramework>
|
||||
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net6;net48</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MartinCostello.Logging.XUnit" Version="0.2.0" />
|
||||
<PackageReference Include="FluentAssertions" Version="6.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="13.2.47" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
|
||||
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
|
||||
<PackageReference Include="AutoMapper" Version="10.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<PackageReference Include="coverlet.msbuild" Version="3.1.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xunit.StaFact" Version="1.0.37" />
|
||||
<PackageReference Include="Moq" Version="4.16.1" />
|
||||
|
||||
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\KubernetesClient.Classic\KubernetesClient.Classic.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
81
tests/KubernetesClient.Classic.Tests/SimpleTests.cs
Normal file
81
tests/KubernetesClient.Classic.Tests/SimpleTests.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using k8s.Models;
|
||||
|
||||
namespace k8s.tests;
|
||||
|
||||
public class BasicTests
|
||||
{
|
||||
// TODO: fail to setup asp.net core 6 on net48
|
||||
private class DummyHttpServer : System.IDisposable
|
||||
{
|
||||
private TcpListener server;
|
||||
private readonly Task loop;
|
||||
private volatile bool running = false;
|
||||
|
||||
public string Addr => $"http://{server.LocalEndpoint}";
|
||||
|
||||
public DummyHttpServer(object obj)
|
||||
{
|
||||
server = new TcpListener(IPAddress.Parse("127.0.0.1"), 0);
|
||||
server.Start();
|
||||
running = true;
|
||||
loop = Task.Run(async () =>
|
||||
{
|
||||
while (running)
|
||||
{
|
||||
var result = KubernetesJson.Serialize(obj);
|
||||
|
||||
var client = await server.AcceptTcpClientAsync().ConfigureAwait(false);
|
||||
var stream = client.GetStream();
|
||||
stream.Read(new byte[1024], 0, 1024); // TODO ensure full header
|
||||
|
||||
var writer = new StreamWriter(stream);
|
||||
await writer.WriteLineAsync("HTTP/1.0 200 OK").ConfigureAwait(false);
|
||||
await writer.WriteLineAsync("Content-Length: " + result.Length).ConfigureAwait(false);
|
||||
await writer.WriteLineAsync("Content-Type: application/json").ConfigureAwait(false);
|
||||
await writer.WriteLineAsync().ConfigureAwait(false);
|
||||
await writer.WriteLineAsync(result).ConfigureAwait(false);
|
||||
|
||||
await writer.FlushAsync().ConfigureAwait(false);
|
||||
client.Close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
running = false;
|
||||
server.Stop();
|
||||
loop.Wait();
|
||||
loop.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task QueryPods()
|
||||
{
|
||||
using var server = new DummyHttpServer(new V1Pod()
|
||||
{
|
||||
Metadata = new V1ObjectMeta()
|
||||
{
|
||||
Name = "pod0",
|
||||
},
|
||||
});
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Addr });
|
||||
|
||||
var pod = await client.ReadNamespacedPodAsync("pod", "default").ConfigureAwait(false);
|
||||
|
||||
Assert.Equal("pod0", pod.Metadata.Name);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>8</LangVersion>
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<RootNamespace>k8s.Tests</RootNamespace>
|
||||
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
Reference in New Issue
Block a user