Implementing a more modular API (#1627)
* fix typo * Add modular API * Use x-kubernetes-action instead of operationId to generate method names * fix * Clean code style warnings * Refactor client constructors to use Kubernetes type instead of IKubernetes * Add ClientSet tests for Kubernetes pod operations * Fix order of parameters in Pod API calls for consistency * Enhance documentation for ClientSet and ResourceClient classes * Refactor ClientSet and GroupClient for Kubernetes usage * Refactor Pod API calls in tests to use singular form for consistency * Refactor Pod API calls to use 'Create' and 'Update' methods for consistency
This commit is contained in:
26
examples/clientset/Program.cs
Normal file
26
examples/clientset/Program.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using k8s;
|
||||
using k8s.ClientSets;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace clientset
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
|
||||
var client = new Kubernetes(config);
|
||||
|
||||
ClientSet clientSet = new ClientSet(client);
|
||||
var list = await clientSet.CoreV1.Pod.ListAsync("default").ConfigureAwait(false);
|
||||
foreach (var item in list)
|
||||
{
|
||||
System.Console.WriteLine(item.Metadata.Name);
|
||||
}
|
||||
|
||||
var pod = await clientSet.CoreV1.Pod.GetAsync("test","default").ConfigureAwait(false);
|
||||
System.Console.WriteLine(pod?.Metadata?.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
6
examples/clientset/clientset.csproj
Normal file
6
examples/clientset/clientset.csproj
Normal file
@@ -0,0 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -46,6 +46,10 @@
|
||||
<Compile Include="..\KubernetesClient\Models\V1Status.cs" />
|
||||
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\KubernetesClient\ClientSets\ClientSet.cs" />
|
||||
<Compile Include="..\KubernetesClient\ClientSets\ResourceClient.cs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\KubernetesClient\AbstractKubernetes.cs" />
|
||||
<Compile Include="..\KubernetesClient\GeneratedApiVersion.cs" />
|
||||
|
||||
@@ -75,7 +75,10 @@
|
||||
<Compile Include="..\KubernetesClient\Autorest\HttpRequestMessageWrapper.cs" />
|
||||
<Compile Include="..\KubernetesClient\Autorest\HttpResponseMessageWrapper.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\KubernetesClient\ClientSets\ClientSet.cs" />
|
||||
<Compile Include="..\KubernetesClient\ClientSets\ResourceClient.cs"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="..\KubernetesClient\FileSystem.cs" />
|
||||
<Compile Include="..\KubernetesClient\IKubernetes.cs" />
|
||||
|
||||
16
src/KubernetesClient/ClientSets/ClientSet.cs
Normal file
16
src/KubernetesClient/ClientSets/ClientSet.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace k8s.ClientSets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a base class for clients that interact with Kubernetes resources.
|
||||
/// Provides shared functionality for derived resource-specific clients.
|
||||
/// </summary>
|
||||
public partial class ClientSet
|
||||
{
|
||||
private readonly Kubernetes _kubernetes;
|
||||
|
||||
public ClientSet(Kubernetes kubernetes)
|
||||
{
|
||||
_kubernetes = kubernetes;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/KubernetesClient/ClientSets/ResourceClient.cs
Normal file
16
src/KubernetesClient/ClientSets/ResourceClient.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
namespace k8s.ClientSets
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a set of Kubernetes clients for interacting with the Kubernetes API.
|
||||
/// This class provides access to various client implementations for managing Kubernetes resources.
|
||||
/// </summary>
|
||||
public abstract class ResourceClient
|
||||
{
|
||||
protected Kubernetes Client { get; }
|
||||
|
||||
public ResourceClient(Kubernetes kubernetes)
|
||||
{
|
||||
Client = kubernetes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@ namespace k8s
|
||||
/// <inheritdoc/>
|
||||
public Task<WebSocket> WebSocketNamespacedPodExecAsync(string name, string @namespace = "default",
|
||||
string command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true,
|
||||
bool tty = true, string webSocketSubProtol = null, Dictionary<string, List<string>> customHeaders = null,
|
||||
bool tty = true, string webSocketSubProtocol = null, Dictionary<string, List<string>> customHeaders = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return WebSocketNamespacedPodExecAsync(name, @namespace, new string[] { command }, container, stderr, stdin,
|
||||
stdout, tty, webSocketSubProtol, customHeaders, cancellationToken);
|
||||
stdout, tty, webSocketSubProtocol, customHeaders, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -30,7 +30,7 @@ namespace k8s
|
||||
string name,
|
||||
string @namespace = "default", IEnumerable<string> command = null, string container = null,
|
||||
bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true,
|
||||
string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol,
|
||||
string webSocketSubProtocol = WebSocketProtocol.V4BinaryWebsocketProtocol,
|
||||
Dictionary<string, List<string>> customHeaders = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -45,7 +45,7 @@ namespace k8s
|
||||
public virtual Task<WebSocket> WebSocketNamespacedPodExecAsync(string name, string @namespace = "default",
|
||||
IEnumerable<string> command = null, string container = null, bool stderr = true, bool stdin = true,
|
||||
bool stdout = true, bool tty = true,
|
||||
string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol,
|
||||
string webSocketSubProtocol = WebSocketProtocol.V4BinaryWebsocketProtocol,
|
||||
Dictionary<string, List<string>> customHeaders = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -114,7 +114,7 @@ namespace k8s
|
||||
uriBuilder.Query =
|
||||
query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it
|
||||
|
||||
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtol, customHeaders,
|
||||
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtocol, customHeaders,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace k8s
|
||||
/// <inheritdoc/>
|
||||
public Task<WebSocket> WebSocketNamespacedPodAttachAsync(string name, string @namespace,
|
||||
string container = default, bool stderr = true, bool stdin = false, bool stdout = true,
|
||||
bool tty = false, string webSocketSubProtol = null, Dictionary<string, List<string>> customHeaders = null,
|
||||
bool tty = false, string webSocketSubProtocol = null, Dictionary<string, List<string>> customHeaders = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (name == null)
|
||||
@@ -208,7 +208,7 @@ namespace k8s
|
||||
uriBuilder.Query =
|
||||
query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it
|
||||
|
||||
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtol, customHeaders,
|
||||
return StreamConnectAsync(uriBuilder.Uri, webSocketSubProtocol, customHeaders,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
103
src/LibKubernetesGenerator/ClientSetGenerator.cs
Normal file
103
src/LibKubernetesGenerator/ClientSetGenerator.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using CaseExtensions;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using NSwag;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace LibKubernetesGenerator
|
||||
{
|
||||
internal class ClientSetGenerator
|
||||
{
|
||||
private readonly ScriptObjectFactory _scriptObjectFactory;
|
||||
|
||||
public ClientSetGenerator(ScriptObjectFactory scriptObjectFactory)
|
||||
{
|
||||
_scriptObjectFactory = scriptObjectFactory;
|
||||
}
|
||||
|
||||
public void Generate(OpenApiDocument swagger, IncrementalGeneratorPostInitializationContext context)
|
||||
{
|
||||
var data = swagger.Operations
|
||||
.Where(o => o.Method != OpenApiOperationMethod.Options)
|
||||
.Select(o =>
|
||||
{
|
||||
var ps = o.Operation.ActualParameters.OrderBy(p => !p.IsRequired).ToArray();
|
||||
|
||||
o.Operation.Parameters.Clear();
|
||||
|
||||
var name = new HashSet<string>();
|
||||
|
||||
var i = 1;
|
||||
foreach (var p in ps)
|
||||
{
|
||||
if (name.Contains(p.Name))
|
||||
{
|
||||
p.Name += i++;
|
||||
}
|
||||
|
||||
o.Operation.Parameters.Add(p);
|
||||
name.Add(p.Name);
|
||||
}
|
||||
|
||||
return o;
|
||||
})
|
||||
.Select(o =>
|
||||
{
|
||||
o.Path = o.Path.TrimStart('/');
|
||||
o.Method = char.ToUpper(o.Method[0]) + o.Method.Substring(1);
|
||||
return o;
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
var sc = _scriptObjectFactory.CreateScriptObject();
|
||||
|
||||
var groups = new List<string>();
|
||||
var apiGroups = new Dictionary<string, OpenApiOperationDescription[]>();
|
||||
|
||||
foreach (var grouped in data.Where(d => HasKubernetesAction(d.Operation?.ExtensionData))
|
||||
.GroupBy(d => d.Operation.Tags.First()))
|
||||
{
|
||||
var clients = new List<string>();
|
||||
var name = grouped.Key.ToPascalCase();
|
||||
groups.Add(name);
|
||||
var apis = grouped.Select(x =>
|
||||
{
|
||||
var groupVersionKindElements = x.Operation?.ExtensionData?["x-kubernetes-group-version-kind"];
|
||||
var groupVersionKind = (Dictionary<string, object>)groupVersionKindElements;
|
||||
|
||||
return new { Kind = groupVersionKind?["kind"] as string, Api = x };
|
||||
});
|
||||
|
||||
foreach (var item in apis.GroupBy(x => x.Kind))
|
||||
{
|
||||
var kind = item.Key;
|
||||
apiGroups[kind] = item.Select(x => x.Api).ToArray();
|
||||
clients.Add(kind);
|
||||
}
|
||||
|
||||
sc.SetValue("clients", clients, true);
|
||||
sc.SetValue("name", name, true);
|
||||
context.RenderToContext("GroupClient.cs.template", sc, $"{name}GroupClient.g.cs");
|
||||
}
|
||||
|
||||
foreach (var apiGroup in apiGroups)
|
||||
{
|
||||
var name = apiGroup.Key;
|
||||
var apis = apiGroup.Value.ToArray();
|
||||
var group = apis.Select(x => x.Operation.Tags[0]).First();
|
||||
sc.SetValue("apis", apis, true);
|
||||
sc.SetValue("name", name, true);
|
||||
sc.SetValue("group", group.ToPascalCase(), true);
|
||||
context.RenderToContext("Client.cs.template", sc, $"{name}Client.g.cs");
|
||||
}
|
||||
|
||||
sc = _scriptObjectFactory.CreateScriptObject();
|
||||
sc.SetValue("groups", groups, true);
|
||||
|
||||
context.RenderToContext("ClientSet.cs.template", sc, $"ClientSet.g.cs");
|
||||
}
|
||||
|
||||
private bool HasKubernetesAction(IDictionary<string, object> extensionData) =>
|
||||
extensionData?.ContainsKey("x-kubernetes-action") ?? false;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,8 @@ namespace LibKubernetesGenerator
|
||||
public void RegisterHelper(ScriptObject scriptObject)
|
||||
{
|
||||
scriptObject.Import(nameof(GetInterfaceName), new Func<JsonSchema, string>(GetInterfaceName));
|
||||
scriptObject.Import(nameof(GetMethodName), new Func<OpenApiOperation, string, string>(GetMethodName));
|
||||
scriptObject.Import(nameof(GetOperationId), new Func<OpenApiOperation, string, string>(GetOperationId));
|
||||
scriptObject.Import(nameof(GetActionName), new Func<OpenApiOperation, string, string, string>(GetActionName));
|
||||
scriptObject.Import(nameof(GetDotNetName), new Func<string, string, string>(GetDotNetName));
|
||||
scriptObject.Import(nameof(GetDotNetNameOpenApiParameter), new Func<OpenApiParameter, string, string>(GetDotNetNameOpenApiParameter));
|
||||
}
|
||||
@@ -138,7 +139,7 @@ namespace LibKubernetesGenerator
|
||||
return jsonName.ToCamelCase();
|
||||
}
|
||||
|
||||
public static string GetMethodName(OpenApiOperation watchOperation, string suffix)
|
||||
public static string GetOperationId(OpenApiOperation watchOperation, string suffix)
|
||||
{
|
||||
var tag = watchOperation.Tags[0];
|
||||
tag = tag.Replace("_", string.Empty);
|
||||
@@ -162,5 +163,28 @@ namespace LibKubernetesGenerator
|
||||
|
||||
return methodName;
|
||||
}
|
||||
|
||||
public static string GetActionName(OpenApiOperation apiOperation, string resource, string suffix)
|
||||
{
|
||||
var operationId = apiOperation.OperationId.ToPascalCase();
|
||||
var replacements = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "Replace", "Update" },
|
||||
{ "Read", "Get" },
|
||||
};
|
||||
|
||||
foreach (var replacement in replacements)
|
||||
{
|
||||
operationId = Regex.Replace(operationId, replacement.Key, replacement.Value, RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
var resources = new[] { resource, "ForAllNamespaces", "Namespaced" };
|
||||
var pattern = string.Join("|", Array.ConvertAll(resources, Regex.Escape));
|
||||
var actionName = pattern.Length > 0
|
||||
? Regex.Replace(operationId, pattern, string.Empty, RegexOptions.IgnoreCase)
|
||||
: operationId;
|
||||
|
||||
return $"{actionName}{suffix}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace LibKubernetesGenerator
|
||||
builder.RegisterType<ModelExtGenerator>();
|
||||
builder.RegisterType<ModelGenerator>();
|
||||
builder.RegisterType<ApiGenerator>();
|
||||
builder.RegisterType<ClientSetGenerator>();
|
||||
builder.RegisterType<VersionConverterStubGenerator>();
|
||||
builder.RegisterType<VersionGenerator>();
|
||||
|
||||
@@ -80,6 +81,7 @@ namespace LibKubernetesGenerator
|
||||
container.Resolve<ModelExtGenerator>().Generate(swagger, ctx);
|
||||
container.Resolve<VersionConverterStubGenerator>().Generate(swagger, ctx);
|
||||
container.Resolve<ApiGenerator>().Generate(swagger, ctx);
|
||||
container.Resolve<ClientSetGenerator>().Generate(swagger, ctx);
|
||||
});
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<!-- Scriban No Dependency -->
|
||||
<PackageReference Include="Scriban" IncludeAssets="Build" />
|
||||
|
||||
|
||||
100
src/LibKubernetesGenerator/templates/Client.cs.template
Normal file
100
src/LibKubernetesGenerator/templates/Client.cs.template
Normal file
@@ -0,0 +1,100 @@
|
||||
// <auto-generated>
|
||||
// Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// </auto-generated>
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace k8s.ClientSets;
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public partial class {{name}}Client : ResourceClient
|
||||
{
|
||||
public {{name}}Client(Kubernetes kubernetes) : base(kubernetes)
|
||||
{
|
||||
}
|
||||
|
||||
{{for api in apis }}
|
||||
/// <summary>
|
||||
/// {{ToXmlDoc api.operation.description}}
|
||||
/// </summary>
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
/// <param name="{{GetDotNetNameOpenApiParameter parameter "false"}}">
|
||||
/// {{ToXmlDoc parameter.description}}
|
||||
/// </param>
|
||||
{{end}}
|
||||
/// <param name="cancellationToken">
|
||||
/// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.
|
||||
/// </param>
|
||||
public async Task{{GetReturnType api.operation "<>"}} {{GetActionName api.operation name "Async"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "true"}},
|
||||
{{ end }}
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
{{if IfReturnType api.operation "stream"}}
|
||||
var _result = await Client.{{group}}.{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
null,
|
||||
cancellationToken);
|
||||
_result.Request.Dispose();
|
||||
{{GetReturnType api.operation "_result.Body"}};
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "obj"}}
|
||||
using (var _result = await Client.{{group}}.{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
null,
|
||||
cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
{{GetReturnType api.operation "_result.Body"}};
|
||||
}
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "void"}}
|
||||
using (var _result = await Client.{{group}}.{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
null,
|
||||
cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
}
|
||||
{{end}}
|
||||
}
|
||||
|
||||
{{if IfReturnType api.operation "object"}}
|
||||
/// <summary>
|
||||
/// {{ToXmlDoc api.operation.description}}
|
||||
/// </summary>
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
/// <param name="{{GetDotNetNameOpenApiParameter parameter "false"}}">
|
||||
/// {{ToXmlDoc parameter.description}}
|
||||
/// </param>
|
||||
{{end}}
|
||||
/// <param name="cancellationToken">
|
||||
/// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.
|
||||
/// </param>
|
||||
public async Task<T> {{GetActionName api.operation name "Async"}}<T>(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{ end }}
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
using (var _result = await Client.{{group}}.{{GetOperationId api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
null,
|
||||
cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
return _result.Body;
|
||||
}
|
||||
}
|
||||
{{end}}
|
||||
{{end}}
|
||||
}
|
||||
16
src/LibKubernetesGenerator/templates/ClientSet.cs.template
Normal file
16
src/LibKubernetesGenerator/templates/ClientSet.cs.template
Normal file
@@ -0,0 +1,16 @@
|
||||
// <auto-generated>
|
||||
// Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// </auto-generated>
|
||||
|
||||
namespace k8s.ClientSets;
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public partial class ClientSet
|
||||
{
|
||||
{{for group in groups}}
|
||||
public {{group}}GroupClient {{group}} => new {{group}}GroupClient(_kubernetes);
|
||||
{{end}}
|
||||
}
|
||||
24
src/LibKubernetesGenerator/templates/GroupClient.cs.template
Normal file
24
src/LibKubernetesGenerator/templates/GroupClient.cs.template
Normal file
@@ -0,0 +1,24 @@
|
||||
// <auto-generated>
|
||||
// Code generated by https://github.com/kubernetes-client/csharp/tree/master/src/LibKubernetesGenerator
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// </auto-generated>
|
||||
|
||||
namespace k8s.ClientSets;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public partial class {{name}}GroupClient
|
||||
{
|
||||
private readonly Kubernetes _kubernetes;
|
||||
|
||||
{{for client in clients}}
|
||||
public {{client}}Client {{client}} => new {{client}}Client(_kubernetes);
|
||||
{{end}}
|
||||
|
||||
public {{name}}GroupClient(Kubernetes kubernetes)
|
||||
{
|
||||
_kubernetes = kubernetes;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public partial interface I{{name}}Operations
|
||||
/// <param name="cancellationToken">
|
||||
/// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.
|
||||
/// </param>
|
||||
Task<HttpOperationResponse{{GetReturnType api.operation "<>"}}> {{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
Task<HttpOperationResponse{{GetReturnType api.operation "<>"}}> {{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "true"}},
|
||||
{{ end }}
|
||||
@@ -47,7 +47,7 @@ public partial interface I{{name}}Operations
|
||||
/// <param name="cancellationToken">
|
||||
/// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.
|
||||
/// </param>
|
||||
Task<HttpOperationResponse<T>> {{GetMethodName api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
Task<HttpOperationResponse<T>> {{GetOperationId api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "true"}},
|
||||
{{ end }}
|
||||
|
||||
@@ -10,13 +10,13 @@ public partial class AbstractKubernetes : I{{name}}Operations
|
||||
{
|
||||
{{for api in apis }}
|
||||
{{if IfReturnType api.operation "void"}}
|
||||
private async Task<HttpOperationResponse> I{{name}}Operations_{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
private async Task<HttpOperationResponse> I{{name}}Operations_{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "obj"}}
|
||||
private async Task<HttpOperationResponse<T>> I{{name}}Operations_{{GetMethodName api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
private async Task<HttpOperationResponse<T>> I{{name}}Operations_{{GetOperationId api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "stream"}}
|
||||
private async Task<HttpOperationResponse<Stream>> I{{name}}Operations_{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
private async Task<HttpOperationResponse<Stream>> I{{name}}Operations_{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{end}}
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
@@ -90,7 +90,7 @@ public partial class AbstractKubernetes : I{{name}}Operations
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
async Task<HttpOperationResponse{{GetReturnType api.operation "<>"}}> I{{name}}Operations.{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
async Task<HttpOperationResponse{{GetReturnType api.operation "<>"}}> I{{name}}Operations.{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -98,7 +98,7 @@ public partial class AbstractKubernetes : I{{name}}Operations
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
{{if IfReturnType api.operation "void"}}
|
||||
return await I{{name}}Operations_{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
return await I{{name}}Operations_{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -106,7 +106,7 @@ public partial class AbstractKubernetes : I{{name}}Operations
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "obj"}}
|
||||
return await I{{name}}Operations_{{GetMethodName api.operation "WithHttpMessagesAsync"}}{{GetReturnType api.operation "<>"}}(
|
||||
return await I{{name}}Operations_{{GetOperationId api.operation "WithHttpMessagesAsync"}}{{GetReturnType api.operation "<>"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -114,7 +114,7 @@ public partial class AbstractKubernetes : I{{name}}Operations
|
||||
cancellationToken).ConfigureAwait(false);
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "stream"}}
|
||||
return await I{{name}}Operations_{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
return await I{{name}}Operations_{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -125,14 +125,14 @@ public partial class AbstractKubernetes : I{{name}}Operations
|
||||
|
||||
{{if IfReturnType api.operation "object"}}
|
||||
/// <inheritdoc/>
|
||||
async Task<HttpOperationResponse<T>> I{{name}}Operations.{{GetMethodName api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
async Task<HttpOperationResponse<T>> I{{name}}Operations.{{GetOperationId api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
IReadOnlyDictionary<string, IReadOnlyList<string>> customHeaders,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return await I{{name}}Operations_{{GetMethodName api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
return await I{{name}}Operations_{{GetOperationId api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
|
||||
@@ -23,14 +23,14 @@ public static partial class {{name}}OperationsExtensions
|
||||
/// {{ToXmlDoc api.description}}
|
||||
/// </param>
|
||||
{{ end }}
|
||||
public static {{GetReturnType api.operation "void"}} {{GetMethodName api.operation ""}}(
|
||||
public static {{GetReturnType api.operation "void"}} {{GetOperationId api.operation ""}}(
|
||||
this I{{name}}Operations operations
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
,{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "true"}}
|
||||
{{end}}
|
||||
)
|
||||
{
|
||||
{{GetReturnType api.operation "return"}} operations.{{GetMethodName api.operation "Async"}}(
|
||||
{{GetReturnType api.operation "return"}} operations.{{GetOperationId api.operation "Async"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -50,14 +50,14 @@ public static partial class {{name}}OperationsExtensions
|
||||
/// {{ToXmlDoc parameter.description}}
|
||||
/// </param>
|
||||
{{end}}
|
||||
public static T {{GetMethodName api.operation ""}}<T>(
|
||||
public static T {{GetOperationId api.operation ""}}<T>(
|
||||
this I{{name}}Operations operations
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
,{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "true"}}
|
||||
{{end}}
|
||||
)
|
||||
{
|
||||
return operations.{{GetMethodName api.operation "Async"}}<T>(
|
||||
return operations.{{GetOperationId api.operation "Async"}}<T>(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -80,7 +80,7 @@ public static partial class {{name}}OperationsExtensions
|
||||
/// <param name="cancellationToken">
|
||||
/// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.
|
||||
/// </param>
|
||||
public static async Task{{GetReturnType api.operation "<>"}} {{GetMethodName api.operation "Async"}}(
|
||||
public static async Task{{GetReturnType api.operation "<>"}} {{GetOperationId api.operation "Async"}}(
|
||||
this I{{name}}Operations operations,
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "true"}},
|
||||
@@ -88,7 +88,7 @@ public static partial class {{name}}OperationsExtensions
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
{{if IfReturnType api.operation "stream"}}
|
||||
var _result = await operations.{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
var _result = await operations.{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -98,7 +98,7 @@ public static partial class {{name}}OperationsExtensions
|
||||
{{GetReturnType api.operation "_result.Body"}};
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "obj"}}
|
||||
using (var _result = await operations.{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
using (var _result = await operations.{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -109,7 +109,7 @@ public static partial class {{name}}OperationsExtensions
|
||||
}
|
||||
{{end}}
|
||||
{{if IfReturnType api.operation "void"}}
|
||||
using (var _result = await operations.{{GetMethodName api.operation "WithHttpMessagesAsync"}}(
|
||||
using (var _result = await operations.{{GetOperationId api.operation "WithHttpMessagesAsync"}}(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
@@ -135,14 +135,14 @@ public static partial class {{name}}OperationsExtensions
|
||||
/// <param name="cancellationToken">
|
||||
/// A <see cref="CancellationToken"/> which can be used to cancel the asynchronous operation.
|
||||
/// </param>
|
||||
public static async Task<T> {{GetMethodName api.operation "Async"}}<T>(
|
||||
public static async Task<T> {{GetOperationId api.operation "Async"}}<T>(
|
||||
this I{{name}}Operations operations,
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetTypeOpenApiParameter parameter}} {{GetDotNetNameOpenApiParameter parameter "true"}},
|
||||
{{ end }}
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
using (var _result = await operations.{{GetMethodName api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
using (var _result = await operations.{{GetOperationId api.operation "WithHttpMessagesAsync"}}<T>(
|
||||
{{ for parameter in api.operation.parameters}}
|
||||
{{GetDotNetNameOpenApiParameter parameter "false"}},
|
||||
{{end}}
|
||||
|
||||
@@ -16,6 +16,7 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using k8s.ClientSets;
|
||||
using Xunit;
|
||||
|
||||
namespace k8s.E2E
|
||||
@@ -584,6 +585,118 @@ namespace k8s.E2E
|
||||
}
|
||||
}
|
||||
|
||||
[MinikubeFact]
|
||||
public async Task ClientSetTest()
|
||||
{
|
||||
var namespaceParameter = "default";
|
||||
var podName = "k8scsharp-e2e-clientset-pod";
|
||||
|
||||
using var kubernetes = CreateClient();
|
||||
|
||||
var clientSet = new ClientSet((Kubernetes)kubernetes);
|
||||
async Task Cleanup()
|
||||
{
|
||||
var pods = await clientSet.CoreV1.Pod.ListAsync(namespaceParameter).ConfigureAwait(false);
|
||||
while (pods.Items.Any(p => p.Metadata.Name == podName))
|
||||
{
|
||||
try
|
||||
{
|
||||
await clientSet.CoreV1.Pod.DeleteAsync(podName, namespaceParameter).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpOperationException e)
|
||||
{
|
||||
if (e.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await Cleanup().ConfigureAwait(false);
|
||||
|
||||
// create + list
|
||||
{
|
||||
await clientSet.CoreV1.Pod.CreateAsync(
|
||||
new V1Pod()
|
||||
{
|
||||
Metadata = new V1ObjectMeta { Name = podName, Labels = new Dictionary<string, string> { { "place", "holder" }, }, },
|
||||
Spec = new V1PodSpec
|
||||
{
|
||||
Containers = new[] { new V1Container() { Name = "k8scsharp-e2e", Image = "nginx", }, },
|
||||
},
|
||||
},
|
||||
namespaceParameter).ConfigureAwait(false);
|
||||
|
||||
var pods = await clientSet.CoreV1.Pod.ListAsync(namespaceParameter).ConfigureAwait(false);
|
||||
Assert.Contains(pods.Items, p => p.Metadata.Name == podName);
|
||||
}
|
||||
|
||||
// replace + get
|
||||
{
|
||||
var pod = await clientSet.CoreV1.Pod.GetAsync(podName, namespaceParameter).ConfigureAwait(false);
|
||||
var old = JsonSerializer.SerializeToDocument(pod);
|
||||
|
||||
var newLabels = new Dictionary<string, string>(pod.Metadata.Labels) { ["test"] = "clientset-test-jsonpatch" };
|
||||
pod.Metadata.Labels = newLabels;
|
||||
|
||||
var expected = JsonSerializer.SerializeToDocument(pod);
|
||||
var patch = old.CreatePatch(expected);
|
||||
|
||||
await clientSet.CoreV1.Pod
|
||||
.PatchAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), podName, namespaceParameter)
|
||||
.ConfigureAwait(false);
|
||||
var pods = await clientSet.CoreV1.Pod.ListAsync(namespaceParameter).ConfigureAwait(false);
|
||||
Assert.Contains(pods.Items, p => p.Labels().Contains(new KeyValuePair<string, string>("test", "clientset-test-jsonpatch")));
|
||||
}
|
||||
|
||||
// replace + get
|
||||
{
|
||||
var pod = await clientSet.CoreV1.Pod.GetAsync(podName, namespaceParameter).ConfigureAwait(false);
|
||||
pod.Spec.Containers[0].Image = "httpd";
|
||||
await clientSet.CoreV1.Pod.UpdateAsync(pod, podName, namespaceParameter).ConfigureAwait(false);
|
||||
|
||||
pod = await clientSet.CoreV1.Pod.GetAsync(podName, namespaceParameter).ConfigureAwait(false);
|
||||
Assert.Equal("httpd", pod.Spec.Containers[0].Image);
|
||||
}
|
||||
|
||||
// delete + list
|
||||
{
|
||||
var pods = new V1PodList();
|
||||
var retry = 5;
|
||||
while (retry-- > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
await clientSet.CoreV1.Pod.DeleteAsync(podName, namespaceParameter).ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpOperationException e)
|
||||
{
|
||||
if (e.Response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pods = await clientSet.CoreV1.Pod.ListAsync(namespaceParameter).ConfigureAwait(false);
|
||||
if (pods.Items.All(p => p.Metadata.Name != podName))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(2.5)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Assert.DoesNotContain(pods.Items, p => p.Metadata.Name == podName);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
await Cleanup().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[MinikubeFact]
|
||||
public async Task CopyToPodTestAsync()
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace k8s.Tests
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
webSocketSubProtol: WebSocketProtocol.ChannelWebSocketProtocol,
|
||||
webSocketSubProtocol: WebSocketProtocol.ChannelWebSocketProtocol,
|
||||
cancellationToken: TestCancellation).ConfigureAwait(true);
|
||||
Assert.Equal(
|
||||
WebSocketProtocol.ChannelWebSocketProtocol,
|
||||
|
||||
Reference in New Issue
Block a user