Version 17.0 + Generate 1.33 (#1626)

* generated based on 1.33

* Update version to 17.0 in version.json

* Remove extra API endpoint from swagger.json

* Remove ModelConverter and related AutoMapper components

* Update package versions

* Refactor code to use ConfigureAwait(false) for asynchronous calls and update target framework to net9.0

* Remove ConfigureAwait(false) from OidcAuthTests for consistency in async calls

* Update SDK version in README to reflect support for net8.0 and net9.0

* Update dotnet SDK version to 9.0.x in build workflow

* Revert Fractions package version to 7.3.0 in Directory.Packages.props

* Update target framework to netstandard2.1 for improved compatibility

* Update package references for Microsoft.CodeAnalysis in Directory.Packages.props and LibKubernetesGenerator.target

* Refactor Worker class constructor documentation and standardize Dictionary type declaration in Program.cs
This commit is contained in:
Boshi Lian
2025-04-27 12:55:24 -07:00
committed by GitHub
parent dfdf0b70d2
commit 001189de77
30 changed files with 10666 additions and 864 deletions

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Directory.Build.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@@ -1,4 +1,5 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Directory.Build.targets" />
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)\..\src\KubernetesClient\KubernetesClient.csproj" Condition="'$(PublishAot)' != 'true'" />
</ItemGroup>

View File

@@ -1,4 +1,4 @@
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Tar;
using k8s;
using System;
using System.IO;
@@ -7,110 +7,104 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace cp
namespace cp;
internal class Cp
{
internal class Cp
private static IKubernetes client;
private static async Task Main(string[] args)
{
private static IKubernetes client;
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
client = new Kubernetes(config);
private static async Task Main(string[] args)
var pods = client.CoreV1.ListNamespacedPod("default", null, null, null, $"job-name=upload-demo");
var pod = pods.Items.First();
await CopyFileToPodAsync(pod.Metadata.Name, "default", "upload-demo", args[0], $"home/{args[1]}").ConfigureAwait(false);
}
private static void ValidatePathParameters(string sourcePath, string destinationPath)
{
if (string.IsNullOrWhiteSpace(sourcePath))
{
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
client = new Kubernetes(config);
var pods = client.CoreV1.ListNamespacedPod("default", null, null, null, $"job-name=upload-demo");
var pod = pods.Items.First();
await CopyFileToPodAsync(pod.Metadata.Name, "default", "upload-demo", args[0], $"home/{args[1]}");
throw new ArgumentException($"{nameof(sourcePath)} cannot be null or whitespace");
}
private static void ValidatePathParameters(string sourcePath, string destinationPath)
if (string.IsNullOrWhiteSpace(destinationPath))
{
if (string.IsNullOrWhiteSpace(sourcePath))
{
throw new ArgumentException($"{nameof(sourcePath)} cannot be null or whitespace");
}
if (string.IsNullOrWhiteSpace(destinationPath))
{
throw new ArgumentException($"{nameof(destinationPath)} cannot be null or whitespace");
}
throw new ArgumentException($"{nameof(destinationPath)} cannot be null or whitespace");
}
}
public static async Task<int> CopyFileToPodAsync(string name, string @namespace, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken))
public static async Task<int> CopyFileToPodAsync(string name, string @namespace, string container, string sourceFilePath, string destinationFilePath, CancellationToken cancellationToken = default(CancellationToken))
{
// All other parameters are being validated by MuxedStreamNamespacedPodExecAsync called by NamespacedPodExecAsync
ValidatePathParameters(sourceFilePath, destinationFilePath);
// The callback which processes the standard input, standard output and standard error of exec method
var handler = new ExecAsyncCallback(async (stdIn, stdOut, stdError) =>
{
// All other parameters are being validated by MuxedStreamNamespacedPodExecAsync called by NamespacedPodExecAsync
ValidatePathParameters(sourceFilePath, destinationFilePath);
// The callback which processes the standard input, standard output and standard error of exec method
var handler = new ExecAsyncCallback(async (stdIn, stdOut, stdError) =>
var fileInfo = new FileInfo(destinationFilePath);
try
{
var fileInfo = new FileInfo(destinationFilePath);
try
using (var memoryStream = new MemoryStream())
{
using (var memoryStream = new MemoryStream())
using (var inputFileStream = File.OpenRead(sourceFilePath))
using (var tarOutputStream = new TarOutputStream(memoryStream, Encoding.Default))
{
using (var inputFileStream = File.OpenRead(sourceFilePath))
using (var tarOutputStream = new TarOutputStream(memoryStream, Encoding.Default))
{
tarOutputStream.IsStreamOwner = false;
tarOutputStream.IsStreamOwner = false;
var fileSize = inputFileStream.Length;
var entry = TarEntry.CreateTarEntry(fileInfo.Name);
var fileSize = inputFileStream.Length;
var entry = TarEntry.CreateTarEntry(fileInfo.Name);
entry.Size = fileSize;
entry.Size = fileSize;
tarOutputStream.PutNextEntry(entry);
await inputFileStream.CopyToAsync(tarOutputStream);
tarOutputStream.CloseEntry();
}
memoryStream.Position = 0;
await memoryStream.CopyToAsync(stdIn);
await stdIn.FlushAsync();
tarOutputStream.PutNextEntry(entry);
await inputFileStream.CopyToAsync(tarOutputStream).ConfigureAwait(false);
tarOutputStream.CloseEntry();
}
memoryStream.Position = 0;
await memoryStream.CopyToAsync(stdIn).ConfigureAwait(false);
await stdIn.FlushAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
throw new IOException($"Copy command failed: {ex.Message}");
}
}
catch (Exception ex)
{
throw new IOException($"Copy command failed: {ex.Message}");
}
using StreamReader streamReader = new StreamReader(stdError);
while (streamReader.EndOfStream == false)
{
string error = await streamReader.ReadToEndAsync();
throw new IOException($"Copy command failed: {error}");
}
});
using StreamReader streamReader = new StreamReader(stdError);
while (streamReader.EndOfStream == false)
{
string error = await streamReader.ReadToEndAsync().ConfigureAwait(false);
throw new IOException($"Copy command failed: {error}");
}
});
string destinationFolder = GetFolderName(destinationFilePath);
string destinationFolder = GetFolderName(destinationFilePath);
return await client.NamespacedPodExecAsync(
name,
@namespace,
container,
new string[] { "sh", "-c", $"tar xmf - -C {destinationFolder}" },
false,
handler,
cancellationToken);
}
return await client.NamespacedPodExecAsync(
name,
@namespace,
container,
new string[] { "sh", "-c", $"tar xmf - -C {destinationFolder}" },
false,
handler,
cancellationToken).ConfigureAwait(false);
}
private static string GetFolderName(string filePath)
{
var folderName = Path.GetDirectoryName(filePath);
return string.IsNullOrEmpty(folderName) ? "." : folderName;
}
private static string GetFolderName(string filePath)
{
var folderName = Path.GetDirectoryName(filePath);
return string.IsNullOrEmpty(folderName) ? "." : folderName;
}
}

View File

@@ -1,4 +1,4 @@
using Json.Patch;
using Json.Patch;
using k8s;
using k8s.Models;
using System.Net;
@@ -44,34 +44,34 @@ var request = new V1CertificateSigningRequest
Kind = "CertificateSigningRequest",
Metadata = new V1ObjectMeta
{
Name = name
Name = name,
},
Spec = new V1CertificateSigningRequestSpec
{
Request = encodedCsr,
SignerName = "kubernetes.io/kube-apiserver-client",
Usages = new List<string> { "client auth" },
ExpirationSeconds = 600 // minimum should be 10 minutes
}
ExpirationSeconds = 600, // minimum should be 10 minutes
},
};
await client.CertificatesV1.CreateCertificateSigningRequestAsync(request);
await client.CertificatesV1.CreateCertificateSigningRequestAsync(request).ConfigureAwait(false);
var serializeOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
WriteIndented = true,
};
var readCert = await client.CertificatesV1.ReadCertificateSigningRequestAsync(name);
var readCert = await client.CertificatesV1.ReadCertificateSigningRequestAsync(name).ConfigureAwait(false);
var old = JsonSerializer.SerializeToDocument(readCert, serializeOptions);
var replace = new List<V1CertificateSigningRequestCondition>
{
new("True", "Approved", DateTime.UtcNow, DateTime.UtcNow, "This certificate was approved by k8s client", "Approve")
new("True", "Approved", DateTime.UtcNow, DateTime.UtcNow, "This certificate was approved by k8s client", "Approve"),
};
readCert.Status.Conditions = replace;
var expected = JsonSerializer.SerializeToDocument(readCert, serializeOptions);
var patch = old.CreatePatch(expected);
await client.CertificatesV1.PatchCertificateSigningRequestApprovalAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name);
await client.CertificatesV1.PatchCertificateSigningRequestApprovalAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name).ConfigureAwait(false);

View File

@@ -29,6 +29,7 @@ foreach (var item in list.Items)
{
Console.WriteLine(item.Metadata.Name);
}
// Or empty if there are no pods
if (list.Items.Count == 0)
{

View File

@@ -28,5 +28,6 @@ static void PrintLabels(V1Pod pod)
{
Console.WriteLine($"{k} : {v}");
}
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=");
}

View File

@@ -18,13 +18,13 @@ namespace portforward
var list = client.CoreV1.ListNamespacedPod("default");
var pod = list.Items[0];
await Forward(client, pod);
await Forward(client, pod).ConfigureAwait(false);
}
private static async Task Forward(IKubernetes client, V1Pod pod)
{
// Note this is single-threaded, it won't handle concurrent requests well...
var webSocket = await client.WebSocketNamespacedPodPortForwardAsync(pod.Metadata.Name, "default", new int[] { 80 }, "v4.channel.k8s.io");
var webSocket = await client.WebSocketNamespacedPodPortForwardAsync(pod.Metadata.Name, "default", new int[] { 80 }, "v4.channel.k8s.io").ConfigureAwait(false);
var demux = new StreamDemuxer(webSocket, StreamType.PortForward);
demux.Start();
@@ -67,12 +67,13 @@ namespace portforward
}
});
await accept;
await copy;
await accept.ConfigureAwait(false);
await copy.ConfigureAwait(false);
if (handler != null)
{
handler.Close();
}
listener.Close();
}
}

View File

@@ -1,17 +1,17 @@
using Json.Patch;
using Json.Patch;
using k8s;
using k8s.Models;
using System.Text.Json;
async Task RestartDaemonSetAsync(string name, string @namespace, IKubernetes client)
{
var daemonSet = await client.AppsV1.ReadNamespacedDaemonSetAsync(name, @namespace);
var daemonSet = await client.AppsV1.ReadNamespacedDaemonSetAsync(name, @namespace).ConfigureAwait(false);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true };
var old = JsonSerializer.SerializeToDocument(daemonSet, options);
var now = DateTimeOffset.Now.ToUnixTimeSeconds();
var restart = new Dictionary<string, string>
{
["date"] = now.ToString()
["date"] = now.ToString(),
};
daemonSet.Spec.Template.Metadata.Annotations = restart;
@@ -19,18 +19,18 @@ async Task RestartDaemonSetAsync(string name, string @namespace, IKubernetes cli
var expected = JsonSerializer.SerializeToDocument(daemonSet);
var patch = old.CreatePatch(expected);
await client.AppsV1.PatchNamespacedDaemonSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace);
await client.AppsV1.PatchNamespacedDaemonSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace).ConfigureAwait(false);
}
async Task RestartDeploymentAsync(string name, string @namespace, IKubernetes client)
{
var deployment = await client.AppsV1.ReadNamespacedDeploymentAsync(name, @namespace);
var deployment = await client.AppsV1.ReadNamespacedDeploymentAsync(name, @namespace).ConfigureAwait(false);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true };
var old = JsonSerializer.SerializeToDocument(deployment, options);
var now = DateTimeOffset.Now.ToUnixTimeSeconds();
var restart = new Dictionary<string, string>
{
["date"] = now.ToString()
["date"] = now.ToString(),
};
deployment.Spec.Template.Metadata.Annotations = restart;
@@ -38,18 +38,18 @@ async Task RestartDeploymentAsync(string name, string @namespace, IKubernetes cl
var expected = JsonSerializer.SerializeToDocument(deployment);
var patch = old.CreatePatch(expected);
await client.AppsV1.PatchNamespacedDeploymentAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace);
await client.AppsV1.PatchNamespacedDeploymentAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace).ConfigureAwait(false);
}
async Task RestartStatefulSetAsync(string name, string @namespace, IKubernetes client)
{
var deployment = await client.AppsV1.ReadNamespacedStatefulSetAsync(name, @namespace);
var deployment = await client.AppsV1.ReadNamespacedStatefulSetAsync(name, @namespace).ConfigureAwait(false);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = true };
var old = JsonSerializer.SerializeToDocument(deployment, options);
var now = DateTimeOffset.Now.ToUnixTimeSeconds();
var restart = new Dictionary<string, string>
{
["date"] = now.ToString()
["date"] = now.ToString(),
};
deployment.Spec.Template.Metadata.Annotations = restart;
@@ -57,12 +57,12 @@ async Task RestartStatefulSetAsync(string name, string @namespace, IKubernetes c
var expected = JsonSerializer.SerializeToDocument(deployment);
var patch = old.CreatePatch(expected);
await client.AppsV1.PatchNamespacedStatefulSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace);
await client.AppsV1.PatchNamespacedStatefulSetAsync(new V1Patch(patch, V1Patch.PatchType.JsonPatch), name, @namespace).ConfigureAwait(false);
}
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
IKubernetes client = new Kubernetes(config);
await RestartDeploymentAsync("event-exporter", "monitoring", client);
await RestartDaemonSetAsync("prometheus-exporter", "monitoring", client);
await RestartStatefulSetAsync("argocd-application-controlle", "argocd", client);
await RestartDeploymentAsync("event-exporter", "monitoring", client).ConfigureAwait(false);
await RestartDaemonSetAsync("prometheus-exporter", "monitoring", client).ConfigureAwait(false);
await RestartStatefulSetAsync("argocd-application-controlle", "argocd", client).ConfigureAwait(false);

View File

@@ -16,7 +16,7 @@ namespace watch
var podlistResp = client.CoreV1.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
// C# 8 required https://docs.microsoft.com/en-us/archive/msdn-magazine/2019/november/csharp-iterating-with-async-enumerables-in-csharp-8
await foreach (var (type, item) in podlistResp.WatchAsync<V1Pod, V1PodList>())
await foreach (var (type, item) in podlistResp.WatchAsync<V1Pod, V1PodList>().ConfigureAwait(false))
{
Console.WriteLine("==on watch event==");
Console.WriteLine(type);
@@ -28,7 +28,9 @@ namespace watch
// WatchUsingCallback(client);
}
#pragma warning disable IDE0051 // Remove unused private members
private static void WatchUsingCallback(IKubernetes client)
#pragma warning restore IDE0051 // Remove unused private members
{
var podlistResp = client.CoreV1.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
using (podlistResp.Watch<V1Pod, V1PodList>((type, item) =>

View File

@@ -14,4 +14,4 @@ IHost host = Host.CreateDefaultBuilder(args)
})
.Build();
await host.RunAsync();
await host.RunAsync().ConfigureAwait(false);

View File

@@ -8,10 +8,11 @@ namespace workerServiceDependencyInjection
private readonly IKubernetes kubernetesClient;
/// <summary>
/// Initializes a new instance of the <see cref="Worker"/> class.
/// Inject in the constructor the IKubernetes interface.
/// </summary>
/// <param name="logger"></param>
/// <param name="kubernetesClient"></param>
/// <param name="logger">The logger instance used for logging information.</param>
/// <param name="kubernetesClient">The Kubernetes client used to interact with the Kubernetes API.</param>
public Worker(ILogger<Worker> logger, IKubernetes kubernetesClient)
{
this.logger = logger;
@@ -33,7 +34,7 @@ namespace workerServiceDependencyInjection
Console.WriteLine(pod.Metadata.Name);
}
await Task.Delay(1000, stoppingToken);
await Task.Delay(1000, stoppingToken).ConfigureAwait(false);
}
}
}

View File

@@ -10,14 +10,14 @@ namespace yaml
{
private static async Task Main(string[] args)
{
var typeMap = new Dictionary<String, Type>
var typeMap = new Dictionary<string, Type>
{
{ "v1/Pod", typeof(V1Pod) },
{ "v1/Service", typeof(V1Service) },
{ "apps/v1/Deployment", typeof(V1Deployment) }
{ "apps/v1/Deployment", typeof(V1Deployment) },
};
var objects = await KubernetesYaml.LoadAllFromFileAsync(args[0], typeMap);
var objects = await KubernetesYaml.LoadAllFromFileAsync(args[0], typeMap).ConfigureAwait(false);
foreach (var obj in objects)
{