Skip to content

Commit 2cf1a53

Browse files
committed
Add modular API
1 parent 19cbf1d commit 2cf1a53

File tree

17 files changed

+545
-34
lines changed

17 files changed

+545
-34
lines changed

examples/clientset/Program.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// See https://aka.ms/new-console-template for more information
2+
using k8s;
3+
using k8s.ClientSets;
4+
using System.Threading.Tasks;
5+
6+
namespace clientset
7+
{
8+
internal class Program
9+
{
10+
private static async Task Main(string[] args)
11+
{
12+
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
13+
IKubernetes client = new Kubernetes(config);
14+
15+
ClientSet clientSet = new ClientSet(client);
16+
var list = await clientSet.CoreV1.Pod.ListNamespacedPodAsync("default").ConfigureAwait(false);
17+
foreach (var item in list)
18+
{
19+
System.Console.WriteLine(item.Metadata.Name);
20+
}
21+
}
22+
}
23+
24+
}

examples/clientset/clientset.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
</PropertyGroup>
5+
6+
</Project>

src/KubernetesClient.Aot/KubernetesClient.Aot.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
<Compile Include="..\KubernetesClient\Models\V1Status.cs" />
4747

4848
</ItemGroup>
49+
<ItemGroup>
50+
<Compile Include="..\KubernetesClient\ClientSets\ClientSet.cs" />
51+
<Compile Include="..\KubernetesClient\ClientSets\ResourceClient.cs"/>
52+
</ItemGroup>
4953
<ItemGroup>
5054
<Compile Include="..\KubernetesClient\AbstractKubernetes.cs" />
5155
<Compile Include="..\KubernetesClient\GeneratedApiVersion.cs" />
@@ -107,4 +111,4 @@
107111
<ItemGroup>
108112
<ProjectReference Include="..\LibKubernetesGenerator\generators\LibKubernetesGenerator\LibKubernetesGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
109113
</ItemGroup>
110-
</Project>
114+
</Project>

src/KubernetesClient.Classic/KubernetesClient.Classic.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@
7575
<Compile Include="..\KubernetesClient\Autorest\HttpRequestMessageWrapper.cs" />
7676
<Compile Include="..\KubernetesClient\Autorest\HttpResponseMessageWrapper.cs" />
7777
</ItemGroup>
78-
78+
<ItemGroup>
79+
<Compile Include="..\KubernetesClient\ClientSets\ClientSet.cs" />
80+
<Compile Include="..\KubernetesClient\ClientSets\ResourceClient.cs"/>
81+
</ItemGroup>
7982
<ItemGroup>
8083
<Compile Include="..\KubernetesClient\FileSystem.cs" />
8184
<Compile Include="..\KubernetesClient\IKubernetes.cs" />

src/KubernetesClient/AbstractKubernetes.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace k8s;
55

66
public abstract partial class AbstractKubernetes
77
{
8-
private static class HttpMethods
8+
internal static class HttpMethods
99
{
1010
public static readonly HttpMethod Delete = HttpMethod.Delete;
1111
public static readonly HttpMethod Get = HttpMethod.Get;
@@ -23,7 +23,7 @@ private static class HttpMethods
2323

2424
}
2525

26-
private sealed class QueryBuilder
26+
internal sealed class QueryBuilder
2727
{
2828
private readonly List<string> parameters = new List<string>();
2929

@@ -99,7 +99,7 @@ private MediaTypeHeaderValue GetHeader(V1Patch body)
9999
}
100100
}
101101

102-
protected abstract Task<HttpOperationResponse<T>> CreateResultAsync<T>(HttpRequestMessage httpRequest, HttpResponseMessage httpResponse, bool? watch, CancellationToken cancellationToken);
102+
internal abstract Task<HttpOperationResponse<T>> CreateResultAsync<T>(HttpRequestMessage httpRequest, HttpResponseMessage httpResponse, bool? watch, CancellationToken cancellationToken);
103103

104-
protected abstract Task<HttpResponseMessage> SendRequest<T>(string relativeUri, HttpMethod method, IReadOnlyDictionary<string, IReadOnlyList<string>> customHeaders, T body, CancellationToken cancellationToken);
104+
internal abstract Task<HttpResponseMessage> SendRequest<T>(string relativeUri, HttpMethod method, IReadOnlyDictionary<string, IReadOnlyList<string>> customHeaders, T body, CancellationToken cancellationToken);
105105
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace k8s.ClientSets;
2+
3+
public partial class ClientSet
4+
{
5+
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace k8s.ClientSets;
2+
3+
public abstract class ResourceClient
4+
{
5+
protected Kubernetes Client { get; }
6+
7+
public ResourceClient(IKubernetes kubernetes)
8+
{
9+
Client = (Kubernetes)kubernetes;
10+
}
11+
}

src/KubernetesClient/GenericClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public GenericClient(IKubernetes kubernetes, string group, string version, strin
3131
public async Task<T> CreateAsync<T>(T obj, CancellationToken cancel = default)
3232
where T : IKubernetesObject
3333
{
34+
3435
var resp = await kubernetes.CustomObjects.CreateClusterCustomObjectWithHttpMessagesAsync<T>(obj, group, version, plural, cancellationToken: cancel).ConfigureAwait(false);
3536
return resp.Body;
3637
}

src/KubernetesClient/Kubernetes.WebSocket.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,19 @@ public partial class Kubernetes
1818
/// <inheritdoc/>
1919
public Task<WebSocket> WebSocketNamespacedPodExecAsync(string name, string @namespace = "default",
2020
string command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true,
21-
bool tty = true, string webSocketSubProtol = null, Dictionary<string, List<string>> customHeaders = null,
21+
bool tty = true, string webSocketSubProtocol = null, Dictionary<string, List<string>> customHeaders = null,
2222
CancellationToken cancellationToken = default)
2323
{
2424
return WebSocketNamespacedPodExecAsync(name, @namespace, new string[] { command }, container, stderr, stdin,
25-
stdout, tty, webSocketSubProtol, customHeaders, cancellationToken);
25+
stdout, tty, webSocketSubProtocol, customHeaders, cancellationToken);
2626
}
2727

2828
/// <inheritdoc/>
2929
public virtual async Task<IStreamDemuxer> MuxedStreamNamespacedPodExecAsync(
3030
string name,
3131
string @namespace = "default", IEnumerable<string> command = null, string container = null,
3232
bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true,
33-
string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol,
33+
string webSocketSubProtocol = WebSocketProtocol.V4BinaryWebsocketProtocol,
3434
Dictionary<string, List<string>> customHeaders = null,
3535
CancellationToken cancellationToken = default)
3636
{
@@ -45,7 +45,7 @@ public virtual async Task<IStreamDemuxer> MuxedStreamNamespacedPodExecAsync(
4545
public virtual Task<WebSocket> WebSocketNamespacedPodExecAsync(string name, string @namespace = "default",
4646
IEnumerable<string> command = null, string container = null, bool stderr = true, bool stdin = true,
4747
bool stdout = true, bool tty = true,
48-
string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol,
48+
string webSocketSubProtocol = WebSocketProtocol.V4BinaryWebsocketProtocol,
4949
Dictionary<string, List<string>> customHeaders = null,
5050
CancellationToken cancellationToken = default)
5151
{
@@ -114,7 +114,7 @@ public virtual Task<WebSocket> WebSocketNamespacedPodExecAsync(string name, stri
114114
uriBuilder.Query =
115115
query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it
116116

117-
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtol, customHeaders,
117+
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtocol, customHeaders,
118118
cancellationToken);
119119
}
120120

@@ -173,7 +173,7 @@ public Task<WebSocket> WebSocketNamespacedPodPortForwardAsync(string name, strin
173173
/// <inheritdoc/>
174174
public Task<WebSocket> WebSocketNamespacedPodAttachAsync(string name, string @namespace,
175175
string container = default, bool stderr = true, bool stdin = false, bool stdout = true,
176-
bool tty = false, string webSocketSubProtol = null, Dictionary<string, List<string>> customHeaders = null,
176+
bool tty = false, string webSocketSubProtocol = null, Dictionary<string, List<string>> customHeaders = null,
177177
CancellationToken cancellationToken = default)
178178
{
179179
if (name == null)
@@ -208,7 +208,7 @@ public Task<WebSocket> WebSocketNamespacedPodAttachAsync(string name, string @na
208208
uriBuilder.Query =
209209
query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it
210210

211-
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtol, customHeaders,
211+
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtocol, customHeaders,
212212
cancellationToken);
213213
}
214214

src/KubernetesClient/Kubernetes.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private void Initialize()
5656
BaseUri = new Uri("http://localhost");
5757
}
5858

59-
protected override async Task<HttpOperationResponse<T>> CreateResultAsync<T>(HttpRequestMessage httpRequest, HttpResponseMessage httpResponse, bool? watch, CancellationToken cancellationToken)
59+
internal override async Task<HttpOperationResponse<T>> CreateResultAsync<T>(HttpRequestMessage httpRequest, HttpResponseMessage httpResponse, bool? watch, CancellationToken cancellationToken)
6060
{
6161
if (httpRequest == null)
6262
{
@@ -96,7 +96,7 @@ protected override async Task<HttpOperationResponse<T>> CreateResultAsync<T>(Htt
9696
return result;
9797
}
9898

99-
protected override Task<HttpResponseMessage> SendRequest<T>(string relativeUri, HttpMethod method, IReadOnlyDictionary<string, IReadOnlyList<string>> customHeaders, T body, CancellationToken cancellationToken)
99+
internal override Task<HttpResponseMessage> SendRequest<T>(string relativeUri, HttpMethod method, IReadOnlyDictionary<string, IReadOnlyList<string>> customHeaders, T body, CancellationToken cancellationToken)
100100
{
101101
var httpRequest = new HttpRequestMessage
102102
{
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
using CaseExtensions;
2+
using Microsoft.CodeAnalysis;
3+
using NSwag;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
7+
namespace LibKubernetesGenerator
8+
{
9+
internal class ClientSetGenerator
10+
{
11+
private readonly ScriptObjectFactory _scriptObjectFactory;
12+
13+
public ClientSetGenerator(ScriptObjectFactory scriptObjectFactory)
14+
{
15+
_scriptObjectFactory = scriptObjectFactory;
16+
}
17+
18+
public void Generate(OpenApiDocument swagger, IncrementalGeneratorPostInitializationContext context)
19+
{
20+
var data = swagger.Operations
21+
.Where(o => o.Method != OpenApiOperationMethod.Options)
22+
.Select(o =>
23+
{
24+
var ps = o.Operation.ActualParameters.OrderBy(p => !p.IsRequired).ToArray();
25+
26+
o.Operation.Parameters.Clear();
27+
28+
var name = new HashSet<string>();
29+
30+
var i = 1;
31+
foreach (var p in ps)
32+
{
33+
if (name.Contains(p.Name))
34+
{
35+
p.Name += i++;
36+
}
37+
38+
o.Operation.Parameters.Add(p);
39+
name.Add(p.Name);
40+
}
41+
42+
return o;
43+
})
44+
.Select(o =>
45+
{
46+
o.Path = o.Path.TrimStart('/');
47+
o.Method = char.ToUpper(o.Method[0]) + o.Method.Substring(1);
48+
return o;
49+
})
50+
.ToArray();
51+
52+
var sc = _scriptObjectFactory.CreateScriptObject();
53+
54+
var groups = new List<string>();
55+
var apiGroups = new Dictionary<string, OpenApiOperationDescription[]>();
56+
57+
foreach (var grouped in data.Where(d => HasKubernetesAction(d.Operation?.ExtensionData))
58+
.GroupBy(d => d.Operation.Tags.First()))
59+
{
60+
var clients = new List<string>();
61+
var name = grouped.Key.ToPascalCase();
62+
groups.Add(name);
63+
var apis = grouped.Select(x =>
64+
{
65+
var groupVersionKindElements = x.Operation?.ExtensionData?["x-kubernetes-group-version-kind"];
66+
var groupVersionKind = (Dictionary<string, object>)groupVersionKindElements;
67+
68+
return new { Kind = groupVersionKind?["kind"], Api = x };
69+
70+
});
71+
72+
foreach (var item in apis.GroupBy(x => x.Kind))
73+
{
74+
var kind = item.Key as string;
75+
apiGroups[kind] = item.Select(x => x.Api).ToArray();
76+
clients.Add(kind);
77+
}
78+
79+
sc.SetValue("clients", clients, true);
80+
sc.SetValue("name", name, true);
81+
context.RenderToContext("GroupClient.cs.template", sc, $"{name}GroupClient.g.cs");
82+
}
83+
84+
foreach (var apiGroup in apiGroups)
85+
{
86+
var name = apiGroup.Key;
87+
var apis = apiGroup.Value.ToArray();
88+
89+
sc.SetValue("apis", apis, true);
90+
sc.SetValue("name", name, true);
91+
context.RenderToContext("Client.cs.template", sc, $"{name}Client.g.cs");
92+
context.RenderToContext("ClientExtensions.cs.template", sc, $"{name}ClientExtensions.g.cs");
93+
}
94+
95+
sc = _scriptObjectFactory.CreateScriptObject();
96+
sc.SetValue("groups", groups, true);
97+
98+
context.RenderToContext("ClientSet.cs.template", sc, $"ClientSet.g.cs");
99+
}
100+
101+
private bool HasKubernetesAction(IDictionary<string, object> extensionData) =>
102+
extensionData?.ContainsKey("x-kubernetes-action") ?? false;
103+
}
104+
}

src/LibKubernetesGenerator/KubernetesClientSourceGenerator.cs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,46 +21,38 @@ private static IContainer BuildContainer(OpenApiDocument swagger)
2121
builder.RegisterType<ClassNameHelper>()
2222
.WithParameter(new NamedParameter(nameof(swagger), swagger))
2323
.AsSelf()
24-
.AsImplementedInterfaces()
25-
;
24+
.AsImplementedInterfaces();
2625

2726
builder.RegisterType<StringHelpers>()
28-
.AsImplementedInterfaces()
29-
;
27+
.AsImplementedInterfaces();
3028

3129
builder.RegisterType<MetaHelper>()
32-
.AsImplementedInterfaces()
33-
;
30+
.AsImplementedInterfaces();
3431

3532
builder.RegisterType<PluralHelper>()
3633
.WithParameter(new TypedParameter(typeof(OpenApiDocument), swagger))
37-
.AsImplementedInterfaces()
38-
;
34+
.AsImplementedInterfaces();
3935

4036
builder.RegisterType<GeneralNameHelper>()
4137
.AsSelf()
42-
.AsImplementedInterfaces()
43-
;
38+
.AsImplementedInterfaces();
4439

4540
builder.RegisterType<TypeHelper>()
4641
.AsSelf()
47-
.AsImplementedInterfaces()
48-
;
42+
.AsImplementedInterfaces();
4943

5044
builder.RegisterType<ParamHelper>()
51-
.AsImplementedInterfaces()
52-
;
45+
.AsImplementedInterfaces();
5346

5447
builder.RegisterType<UtilHelper>()
55-
.AsImplementedInterfaces()
56-
;
48+
.AsImplementedInterfaces();
5749

58-
builder.RegisterType<ScriptObjectFactory>()
59-
;
50+
builder.RegisterType<ScriptObjectFactory>();
6051

6152
builder.RegisterType<ModelExtGenerator>();
6253
builder.RegisterType<ModelGenerator>();
6354
builder.RegisterType<ApiGenerator>();
55+
builder.RegisterType<ClientSetGenerator>();
6456
builder.RegisterType<VersionConverterStubGenerator>();
6557
builder.RegisterType<VersionGenerator>();
6658

@@ -80,6 +72,7 @@ public void Initialize(IncrementalGeneratorInitializationContext generatorContex
8072
container.Resolve<ModelExtGenerator>().Generate(swagger, ctx);
8173
container.Resolve<VersionConverterStubGenerator>().Generate(swagger, ctx);
8274
container.Resolve<ApiGenerator>().Generate(swagger, ctx);
75+
container.Resolve<ClientSetGenerator>().Generate(swagger, ctx);
8376
});
8477
#endif
8578

0 commit comments

Comments
 (0)