Skip to content

Commit 8575548

Browse files
authored
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 5cdaf59.
1 parent 92ccac4 commit 8575548

File tree

10 files changed

+225
-5
lines changed

10 files changed

+225
-5
lines changed

kubernetes-client.sln

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "yaml", "examples\yaml\yaml.
5151
EndProject
5252
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Models", "src\KubernetesClient.Models\KubernetesClient.Models.csproj", "{F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8}"
5353
EndProject
54-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesClient.Basic", "src\KubernetesClient.Basic\KubernetesClient.Basic.csproj", "{927995F5-05CC-4078-8805-8E6CC06914D8}"
54+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Basic", "src\KubernetesClient.Basic\KubernetesClient.Basic.csproj", "{927995F5-05CC-4078-8805-8E6CC06914D8}"
55+
EndProject
56+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesClient.Classic", "src\KubernetesClient.Classic\KubernetesClient.Classic.csproj", "{80F19E8A-F097-4AA4-A68C-D417B96BBC68}"
57+
EndProject
58+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KubernetesClient.Classic.Tests", "tests\KubernetesClient.Classic.Tests\KubernetesClient.Classic.Tests.csproj", "{FD90C861-56C6-4536-B7F5-AC7779296384}"
5559
EndProject
5660
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csrApproval", "examples\csrApproval\csrApproval.csproj", "{F626860C-F141-45B3-9DDD-88AD3932ACAF}"
5761
EndProject
@@ -329,6 +333,30 @@ Global
329333
{927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x64.Build.0 = Release|Any CPU
330334
{927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x86.ActiveCfg = Release|Any CPU
331335
{927995F5-05CC-4078-8805-8E6CC06914D8}.Release|x86.Build.0 = Release|Any CPU
336+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
337+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|Any CPU.Build.0 = Debug|Any CPU
338+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x64.ActiveCfg = Debug|Any CPU
339+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x64.Build.0 = Debug|Any CPU
340+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x86.ActiveCfg = Debug|Any CPU
341+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Debug|x86.Build.0 = Debug|Any CPU
342+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|Any CPU.ActiveCfg = Release|Any CPU
343+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|Any CPU.Build.0 = Release|Any CPU
344+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x64.ActiveCfg = Release|Any CPU
345+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x64.Build.0 = Release|Any CPU
346+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x86.ActiveCfg = Release|Any CPU
347+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68}.Release|x86.Build.0 = Release|Any CPU
348+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
349+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|Any CPU.Build.0 = Debug|Any CPU
350+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x64.ActiveCfg = Debug|Any CPU
351+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x64.Build.0 = Debug|Any CPU
352+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x86.ActiveCfg = Debug|Any CPU
353+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Debug|x86.Build.0 = Debug|Any CPU
354+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|Any CPU.ActiveCfg = Release|Any CPU
355+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|Any CPU.Build.0 = Release|Any CPU
356+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x64.ActiveCfg = Release|Any CPU
357+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x64.Build.0 = Release|Any CPU
358+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x86.ActiveCfg = Release|Any CPU
359+
{FD90C861-56C6-4536-B7F5-AC7779296384}.Release|x86.Build.0 = Release|Any CPU
332360
{F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
333361
{F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
334362
{F626860C-F141-45B3-9DDD-88AD3932ACAF}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -368,6 +396,8 @@ Global
368396
{17AB0AD8-6C90-42DD-880C-16B5AC4A373F} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
369397
{F066A4D8-2EF0-4C07-AC0D-BD325DE3FFA8} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
370398
{927995F5-05CC-4078-8805-8E6CC06914D8} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
399+
{80F19E8A-F097-4AA4-A68C-D417B96BBC68} = {3D1864AA-1FFC-4512-BB13-46055E410F73}
400+
{FD90C861-56C6-4536-B7F5-AC7779296384} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509}
371401
{F626860C-F141-45B3-9DDD-88AD3932ACAF} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40}
372402
EndGlobalSection
373403
GlobalSection(ExtensibilityGlobals) = postSolution
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
global using System;
2+
global using System.Collections.Generic;
3+
global using System.Linq;
4+
global using System.Text.Json;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>netstandard2.0;net48</TargetFrameworks>
5+
<RootNamespace>k8s</RootNamespace>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
10+
<PackageReference Include="System.IO.Abstractions" Version="13.2.47" />
11+
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.13.1" />
12+
<PackageReference Include="IdentityModel.OidcClient" Version="4.0.0" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\KubernetesClient.Models\KubernetesClient.Models.csproj" />
17+
<ProjectReference Include="..\KubernetesClient.Basic\KubernetesClient.Basic.csproj" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<Compile Include="..\KubernetesClient\CertUtils.cs" />
22+
<Compile Include="..\KubernetesClient\FileUtils.cs" />
23+
<Compile Include="..\KubernetesClient\IKubernetes.cs" />
24+
<Compile Include="..\KubernetesClient\Kubernetes.ConfigInit.cs" />
25+
<Compile Include="..\KubernetesClient\Kubernetes.cs" />
26+
<Compile Include="..\KubernetesClient\KubernetesClientConfiguration.ConfigFile.cs" />
27+
<Compile Include="..\KubernetesClient\KubernetesClientConfiguration.InCluster.cs" />
28+
<Compile Include="..\KubernetesClient\KubernetesClientConfiguration.cs" />
29+
<Compile Include="..\KubernetesClient\KubernetesException.cs" />
30+
31+
<Compile Include="..\KubernetesClient\Exceptions\KubeConfigException.cs" />
32+
<Compile Include="..\KubernetesClient\Exceptions\KubernetesClientException.cs" />
33+
34+
<Compile Include="..\KubernetesClient\Authentication\ExecTokenProvider.cs" />
35+
<Compile Include="..\KubernetesClient\Authentication\GcpTokenProvider.cs" />
36+
<Compile Include="..\KubernetesClient\Authentication\OidcTokenProvider.cs" />
37+
<Compile Include="..\KubernetesClient\Authentication\TokenFileAuth.cs" />
38+
</ItemGroup>
39+
40+
<ItemGroup>
41+
<Reference Include="System.Net.Http" Condition="'$(TargetFramework)' == 'net48'" />
42+
</ItemGroup>
43+
</Project>

src/KubernetesClient/Authentication/TokenFileAuth.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,21 @@ public TokenFileAuth(string tokenFile)
1717
TokenFile = tokenFile;
1818
}
1919

20+
#if NETSTANDARD2_1_OR_GREATER
2021
public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
22+
#else
23+
public Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
24+
#endif
2125
{
2226
if (TokenExpiresAt < DateTime.UtcNow)
2327
{
28+
#if NETSTANDARD2_1_OR_GREATER
2429
token = await File.ReadAllTextAsync(TokenFile, cancellationToken)
2530
.ContinueWith(r => r.Result.Trim(), cancellationToken)
2631
.ConfigureAwait(false);
32+
#else
33+
token = File.ReadAllText(TokenFile).Trim();
34+
#endif
2735
// in fact, the token has a expiry of 10 minutes and kubelet
2836
// refreshes it at 8 minutes of its lifetime. setting the expiry
2937
// of 1 minute makes sure the token is reloaded regularly so
@@ -32,8 +40,11 @@ public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(Cancel
3240
// < 10-8-1 minute.
3341
TokenExpiresAt = DateTime.UtcNow.AddMinutes(1);
3442
}
35-
43+
#if NETSTANDARD2_1_OR_GREATER
3644
return new AuthenticationHeaderValue("Bearer", token);
45+
#else
46+
return Task.FromResult(new AuthenticationHeaderValue("Bearer", token));
47+
#endif
3748
}
3849
}
3950
}

src/KubernetesClient/Kubernetes.ConfigInit.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ public Kubernetes(KubernetesClientConfiguration config, params DelegatingHandler
2323
Initialize();
2424
ValidateConfig(config);
2525
CaCerts = config.SslCaCerts;
26+
#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
2627
SkipTlsVerify = config.SkipTlsVerify;
28+
#endif
2729
CreateHttpClient(handlers, config);
2830
InitializeFromConfig(config);
2931
HttpClientTimeout = config.HttpClientTimeout;
@@ -100,9 +102,11 @@ private void InitializeFromConfig(KubernetesClientConfiguration config)
100102

101103
private X509Certificate2Collection CaCerts { get; }
102104

105+
#if NETSTANDARD2_1_OR_GREATER || NET5_0_OR_GREATER
103106
private X509Certificate2 ClientCert { get; }
104107

105108
private bool SkipTlsVerify { get; }
109+
#endif
106110

107111
// NOTE: this method replicates the logic that the base ServiceClient uses except that it doesn't insert the RetryDelegatingHandler
108112
// and it does insert the WatcherDelegatingHandler. we don't want the RetryDelegatingHandler because it has a very broad definition

src/KubernetesClient/Kubernetes.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ protected override async Task<HttpOperationResponse<T>> CreateResultAsync<T>(Htt
7171

7272
if (watch == true)
7373
{
74+
#if NETSTANDARD2_0 || NET48
75+
throw new KubernetesException("watch not supported");
76+
#else
7477
httpResponse.Content = new LineSeparatedHttpContent(httpResponse.Content, cancellationToken);
78+
#endif
7579
}
7680

7781
try
@@ -100,7 +104,9 @@ protected override HttpRequestMessage CreateRequest(string relativeUri, string m
100104
var httpRequest = new HttpRequestMessage();
101105
httpRequest.Method = new HttpMethod(method);
102106
httpRequest.RequestUri = new Uri(BaseUri, relativeUri);
107+
#if NETSTANDARD2_1_OR_GREATER
103108
httpRequest.Version = HttpVersion.Version20;
109+
#endif
104110
// Set Headers
105111
if (customHeaders != null)
106112
{

src/nuget.proj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
<ProjectReference Include="KubernetesClient.Models/KubernetesClient.Models.csproj" />
44
<ProjectReference Include="KubernetesClient.Basic/KubernetesClient.Basic.csproj" />
55
<ProjectReference Include="KubernetesClient/KubernetesClient.csproj" />
6+
<ProjectReference Include="KubernetesClient.Classic/KubernetesClient.Classic.csproj" />
67
</ItemGroup>
78
</Project>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<IsPackable>false</IsPackable>
4+
<RootNamespace>k8s.Tests</RootNamespace>
5+
<TargetFramework Condition="'$(OS)' != 'Windows_NT'">net6</TargetFramework>
6+
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net6;net48</TargetFrameworks>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="MartinCostello.Logging.XUnit" Version="0.2.0" />
11+
<PackageReference Include="FluentAssertions" Version="6.1.0" />
12+
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
13+
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="13.2.47" />
14+
<PackageReference Include="System.Reactive" Version="5.0.0" />
15+
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
16+
<PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
17+
<PackageReference Include="AutoMapper" Version="10.1.1" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
22+
<PackageReference Include="coverlet.msbuild" Version="3.1.0">
23+
<PrivateAssets>all</PrivateAssets>
24+
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
25+
</PackageReference>
26+
27+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
28+
<PackageReference Include="xunit" Version="2.4.1" />
29+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
30+
<PrivateAssets>all</PrivateAssets>
31+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
32+
</PackageReference>
33+
<PackageReference Include="Xunit.StaFact" Version="1.0.37" />
34+
<PackageReference Include="Moq" Version="4.16.1" />
35+
36+
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
37+
</ItemGroup>
38+
39+
<ItemGroup>
40+
<ProjectReference Include="..\..\src\KubernetesClient.Classic\KubernetesClient.Classic.csproj" />
41+
</ItemGroup>
42+
</Project>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System.IO;
2+
using System.Net;
3+
using System.Net.Sockets;
4+
using System.Threading.Tasks;
5+
using Xunit;
6+
using k8s.Models;
7+
8+
namespace k8s.tests;
9+
10+
public class BasicTests
11+
{
12+
// TODO: fail to setup asp.net core 6 on net48
13+
private class DummyHttpServer : System.IDisposable
14+
{
15+
private TcpListener server;
16+
private readonly Task loop;
17+
private volatile bool running = false;
18+
19+
public string Addr => $"http://{server.LocalEndpoint}";
20+
21+
public DummyHttpServer(object obj)
22+
{
23+
server = new TcpListener(IPAddress.Parse("127.0.0.1"), 0);
24+
server.Start();
25+
running = true;
26+
loop = Task.Run(async () =>
27+
{
28+
while (running)
29+
{
30+
var result = KubernetesJson.Serialize(obj);
31+
32+
var client = await server.AcceptTcpClientAsync().ConfigureAwait(false);
33+
var stream = client.GetStream();
34+
stream.Read(new byte[1024], 0, 1024); // TODO ensure full header
35+
36+
var writer = new StreamWriter(stream);
37+
await writer.WriteLineAsync("HTTP/1.0 200 OK").ConfigureAwait(false);
38+
await writer.WriteLineAsync("Content-Length: " + result.Length).ConfigureAwait(false);
39+
await writer.WriteLineAsync("Content-Type: application/json").ConfigureAwait(false);
40+
await writer.WriteLineAsync().ConfigureAwait(false);
41+
await writer.WriteLineAsync(result).ConfigureAwait(false);
42+
43+
await writer.FlushAsync().ConfigureAwait(false);
44+
client.Close();
45+
}
46+
});
47+
}
48+
49+
public void Dispose()
50+
{
51+
try
52+
{
53+
running = false;
54+
server.Stop();
55+
loop.Wait();
56+
loop.Dispose();
57+
}
58+
catch
59+
{
60+
// ignore
61+
}
62+
}
63+
}
64+
65+
[Fact]
66+
public async Task QueryPods()
67+
{
68+
using var server = new DummyHttpServer(new V1Pod()
69+
{
70+
Metadata = new V1ObjectMeta()
71+
{
72+
Name = "pod0",
73+
},
74+
});
75+
var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Addr });
76+
77+
var pod = await client.ReadNamespacedPodAsync("pod", "default").ConfigureAwait(false);
78+
79+
Assert.Equal("pod0", pod.Metadata.Name);
80+
}
81+
}

tests/KubernetesClient.Tests/KubernetesClient.Tests.csproj

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
22
<PropertyGroup>
33
<IsPackable>false</IsPackable>
4-
<LangVersion>8</LangVersion>
5-
<SignAssembly>true</SignAssembly>
64
<RootNamespace>k8s.Tests</RootNamespace>
75
<TargetFrameworks>netcoreapp3.1;net5.0;net6.0</TargetFrameworks>
86
</PropertyGroup>

0 commit comments

Comments
 (0)