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:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -28,5 +28,6 @@ static void PrintLabels(V1Pod pod)
|
||||
{
|
||||
Console.WriteLine($"{k} : {v}");
|
||||
}
|
||||
|
||||
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=");
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) =>
|
||||
|
||||
@@ -14,4 +14,4 @@ IHost host = Host.CreateDefaultBuilder(args)
|
||||
})
|
||||
.Build();
|
||||
|
||||
await host.RunAsync();
|
||||
await host.RunAsync().ConfigureAwait(false);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user