Squashed commit of the following: (#492)
commit dc93612024202e651a9cbe4194c1495c823bff12
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 16:24:33 2020 -0700
fix SA1505
commit dc9fdbc4a4fbce7f4362a24e1ff98be4d27e16a8
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 16:24:02 2020 -0700
add ()
commit 16fb7357fcd7e288a4b8fb201fda2b0aae92e5bc
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 16:21:37 2020 -0700
disable SA1117
commit 544a7e5891e853e2e222f855e5446f3fd79ce2ba
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 16:21:16 2020 -0700
fix SA1508
commit 4e998adf440dda4f13512d1e10f8cb5d5fbc6bd9
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 16:08:28 2020 -0700
allow sa1623
commit baf787255c657a00a6074598c6875e0ab4c9d065
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 16:07:23 2020 -0700
fix SA1413
commit 5ef2ca65de62e6c3cbe513902e3954d78f6dc315
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 16:05:45 2020 -0700
fix SA1413
commit 6cb71f08060b8252a18b01a5788eb2ddcee67c3e
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:44:55 2020 -0700
fix throw stack
commit e6ada0b1cb3aa72df5fcaa0b4690aadcbd4bda5a
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:44:35 2020 -0700
allow CA2225
commit 2e79edec5843c20b7e8f8e9ec5b61cf95284466a
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:35:50 2020 -0700
allow SA1507
commit 108f5a6361f4faa211a8e01f783803295fac0453
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:35:31 2020 -0700
force SA1413
commit 20f33b64972bfafeada513ae1a46a030934673fd
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:30:58 2020 -0700
force SA1413
commit 6b0de102d68a116e149868731e155bc374f56cc8
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:28:33 2020 -0700
fix encoding
commit 4bd8892c2f0e0fa3666e59b0b77f5b23a2e4ca50
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:26:00 2020 -0700
fix xunit order
commit e28556b37ecd782df2d740321e782622ecd277ca
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:10:20 2020 -0700
fix spacing SA1012 SA1004
commit e8cf4b1e0be951babe04cc3674e17718319b8476
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:04:44 2020 -0700
fix SA1211
commit b4164446f7f9d82fb872243e59e3f5c46fbb1f3c
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 06:02:34 2020 -0700
fix attribute related warning
commit 2f17ef45947f6ade36593ede6ba4d27bd1991508
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 05:56:53 2020 -0700
allow ca1801 ca1052 ca1054
commit 49b857f3f1b4a44a809c9186108caab0412c101e
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 05:50:07 2020 -0700
fix SA1001
commit 3389662a32cfc481a3fdf50b6fd651e23aadd9dd
Author: Boshi LIAN <bolian@microsoft.com>
Date: Fri Oct 9 06:24:32 2020 -0700
fix dotnet format
commit f9d55fc925e8a7d2f2b403bd3ae35673068134da
Merge: 8e81532 0d68823
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 05:44:30 2020 -0700
Merge branch 'master' into style_fix0
commit 8e815324040837714efb323580cc5dcd79e58310
Author: Boshi Lian <farmer1992@gmail.com>
Date: Fri Oct 9 05:33:02 2020 -0700
fix remaing build err
commit ecf0152f9e989c4c68274b488d4b3ed6ee88daf9
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 05:24:00 2020 -0700
fix SA1707
commit 462d94794848ebfcd102b56a4344ffc33b50f591
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 05:19:38 2020 -0700
fix underscore naming
commit 5271b113603e469021348523f19555e6be22aebc
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 05:19:12 2020 -0700
allow CA1822
commit 602713ce631026e88d8ff7e8803bb12c2addc3c2
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:37:16 2020 -0700
fix CA1822
commit bd4fee4d31c1054eadf6d03aa10f443eee9654c0
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:36:36 2020 -0700
fix CA1822
commit 257d461f21ef7df65fbc787d5c42c59a89d0eced
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:34:25 2020 -0700
introduce dispose pattern
commit 1d668c7926f877ea196edb67acbfe9bfeddb9e15
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:23:09 2020 -0700
allow CA2008
commit e4fa6acaf36b84298c8c2ab125ff8aa9efc097b7
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:20:28 2020 -0700
allow CA1827
commit dd931d99fa3a95f936ed566320fffa85efb22838
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:14:35 2020 -0700
allow SA1314 CA1825
commit 13b6cf11df439be8020e17bc5d30addc62f90c39
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:13:51 2020 -0700
Revert "fix CA1825"
This reverts commit 17e03bcd4e0f129a64e57d54fbe72acb7d1d226b.
commit 368664139c75d61ab5a0c432a7fbbdad956c54cf
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:09:52 2020 -0700
move class to single files
commit 0015631805d6bc31e4695881989058bb3955766f
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:09:27 2020 -0700
disable CA2000 / TODO
commit 0a1241e84ba1247c8ab4ab8d32bd5d800114420b
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:07:23 2020 -0700
allow SA1715
commit 17e03bcd4e0f129a64e57d54fbe72acb7d1d226b
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 04:06:57 2020 -0700
fix CA1825
commit 7baf350ca93cb45e2587d86fb6ab6e4cf665b6da
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 03:42:04 2020 -0700
fix SA1312 SA1306
commit 44ad5934182adfc871215637e9612295bc26e6f2
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 03:30:35 2020 -0700
fix CA2007
commit 325fa2c2d16d541db6e21b791c5170f39f832d43
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 03:25:11 2020 -0700
fix SA1131
commit 8f1f46b065dd7e9b316491676bb0b93ef91d0595
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 03:17:08 2020 -0700
allow SA1119
commit 57c0fe7cc26932cc30b4d7cc75a809746d74d5aa
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 03:14:14 2020 -0700
fix SA1400
commit 0afcbbc09d5ef66fbbd4b291d14e7804a8e5a1d3
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 03:12:18 2020 -0700
fix SA1513
commit 45f2424531d35a2a106e10e788aff1a18d745078
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 03:09:17 2020 -0700
allow ca1720 ca1716 sa1405
commit 3403814130a1bf730c4e275f74e9cf5d03bedb41
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:16:37 2020 -0700
fix model oper not contains generated header
commit 11377d916cf8cd3ad9109388aff6cf989ff4b7b0
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:14:05 2020 -0700
fix SA1649
commit 92b00051a8c80542a63e1dddbb6eed4e98ad26f9
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:11:16 2020 -0700
fix SA1124
commit 901a9dd2426fa316bcc5a3c2fc411e583f0e07df
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:09:27 2020 -0700
save 1122
commit a8f17b6bac1f1c115b7ed9ebb70d16697a3e81b7
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:09:07 2020 -0700
1507 followup
commit a143184921abb38a09e28a7ef07379003fb19563
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:07:38 2020 -0700
fix sa1507
commit 54b56026265cbbbfa6e5b8b4dcfab281ffbfa272
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:06:44 2020 -0700
fix sa1513
commit 53a009205c88a1d63d8daf32599bbc6428619638
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:05:36 2020 -0700
fix SA1649
commit 26d3e78f61ffc381887baaf5c8b56d92aa0ec563
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 02:01:01 2020 -0700
fix ca1816
commit 1ce5a04ce7a32d901cbece3e18d59e3c068cfd27
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed Oct 7 01:56:43 2020 -0700
readable ruleset
commit dafc55f1c2cdc8466919276291333ba46176161a
Author: Boshi Lian <farmer1992@gmail.com>
Date: Wed May 27 19:13:56 2020 -0700
sync none from guideline
This commit is contained in:
@@ -18,14 +18,14 @@ namespace attach
|
||||
|
||||
var list = client.ListNamespacedPod("default");
|
||||
var pod = list.Items[0];
|
||||
await AttachToPod(client, pod);
|
||||
await AttachToPod(client, pod).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async static Task AttachToPod(IKubernetes client, V1Pod pod)
|
||||
{
|
||||
var webSocket =
|
||||
await client.WebSocketNamespacedPodAttachAsync(pod.Metadata.Name, "default",
|
||||
pod.Spec.Containers[0].Name);
|
||||
pod.Spec.Containers[0].Name).ConfigureAwait(false);
|
||||
|
||||
var demux = new StreamDemuxer(webSocket);
|
||||
demux.Start();
|
||||
|
||||
@@ -15,14 +15,14 @@ namespace exec
|
||||
|
||||
var list = client.ListNamespacedPod("default");
|
||||
var pod = list.Items[0];
|
||||
await ExecInPod(client, pod);
|
||||
await ExecInPod(client, pod).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async static Task ExecInPod(IKubernetes client, V1Pod pod)
|
||||
{
|
||||
var webSocket =
|
||||
await client.WebSocketNamespacedPodExecAsync(pod.Metadata.Name, "default", "ls",
|
||||
pod.Spec.Containers[0].Name);
|
||||
pod.Spec.Containers[0].Name).ConfigureAwait(false);
|
||||
|
||||
var demux = new StreamDemuxer(webSocket);
|
||||
demux.Start();
|
||||
|
||||
@@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||
namespace httpClientFactory
|
||||
{
|
||||
// Learn more about IHostedServices at https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services?view=aspnetcore-2.2&tabs=visual-studio
|
||||
internal class PodListHostedService : IHostedService
|
||||
public class PodListHostedService : IHostedService
|
||||
{
|
||||
private readonly IKubernetes _kubernetesClient;
|
||||
private readonly ILogger<PodListHostedService> _logger;
|
||||
@@ -23,7 +23,7 @@ namespace httpClientFactory
|
||||
{
|
||||
_logger.LogInformation("Starting Request!");
|
||||
|
||||
var list = await _kubernetesClient.ListNamespacedPodAsync("default", cancellationToken: cancellationToken);
|
||||
var list = await _kubernetesClient.ListNamespacedPodAsync("default", cancellationToken: cancellationToken).ConfigureAwait(false);
|
||||
foreach (var item in list.Items)
|
||||
{
|
||||
_logger.LogInformation(item.Metadata.Name);
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace logs
|
||||
var pod = list.Items[0];
|
||||
|
||||
var response = await client.ReadNamespacedPodLogWithHttpMessagesAsync(pod.Metadata.Name,
|
||||
pod.Metadata.NamespaceProperty, follow: true);
|
||||
pod.Metadata.NamespaceProperty, follow: true).ConfigureAwait(false);
|
||||
var stream = response.Body;
|
||||
stream.CopyTo(Console.OpenStandardOutput());
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace metrics
|
||||
{
|
||||
class Program
|
||||
internal class Program
|
||||
{
|
||||
static async Task NodesMetrics(IKubernetes client)
|
||||
private static async Task NodesMetrics(IKubernetes client)
|
||||
{
|
||||
var nodesMetrics = await client.GetKubernetesNodesMetricsAsync().ConfigureAwait(false);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace metrics
|
||||
}
|
||||
}
|
||||
|
||||
static async Task PodsMetrics(IKubernetes client)
|
||||
private static async Task PodsMetrics(IKubernetes client)
|
||||
{
|
||||
var podsMetrics = await client.GetKubernetesPodsMetricsAsync().ConfigureAwait(false);
|
||||
|
||||
@@ -42,11 +42,12 @@ namespace metrics
|
||||
Console.WriteLine($"{metric.Key}: {metric.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.Write(Environment.NewLine);
|
||||
}
|
||||
}
|
||||
|
||||
static async Task Main(string[] args)
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
var config = KubernetesClientConfiguration.BuildConfigFromConfigFile();
|
||||
var client = new Kubernetes(config);
|
||||
@@ -6,9 +6,9 @@ using k8s.Models;
|
||||
|
||||
namespace @namespace
|
||||
{
|
||||
class NamespaceExample
|
||||
internal class NamespaceExample
|
||||
{
|
||||
static void ListNamespaces(IKubernetes client)
|
||||
private static void ListNamespaces(IKubernetes client)
|
||||
{
|
||||
var list = client.ListNamespace();
|
||||
foreach (var item in list.Items)
|
||||
@@ -22,14 +22,14 @@ namespace @namespace
|
||||
}
|
||||
}
|
||||
|
||||
static async Task DeleteAsync(IKubernetes client, string name, int delayMillis)
|
||||
private static async Task DeleteAsync(IKubernetes client, string name, int delayMillis)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
await Task.Delay(delayMillis);
|
||||
await Task.Delay(delayMillis).ConfigureAwait(false);
|
||||
try
|
||||
{
|
||||
await client.ReadNamespaceAsync(name);
|
||||
await client.ReadNamespaceAsync(name).ConfigureAwait(false);
|
||||
}
|
||||
catch (AggregateException ex)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace @namespace
|
||||
return;
|
||||
}
|
||||
|
||||
throw ex;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,12 +54,12 @@ namespace @namespace
|
||||
return;
|
||||
}
|
||||
|
||||
throw ex;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Delete(IKubernetes client, string name, int delayMillis)
|
||||
private static void Delete(IKubernetes client, string name, int delayMillis)
|
||||
{
|
||||
DeleteAsync(client, name, delayMillis).Wait();
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// <auto-generated>
|
||||
// Code generated by gen/KubernetesWatchGenerator
|
||||
// Changes may cause incorrect behavior and will be lost if the code is
|
||||
// regenerated.
|
||||
// </auto-generated>
|
||||
using k8s.Versioning;
|
||||
|
||||
namespace k8s.Models
|
||||
|
||||
@@ -11,15 +11,15 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace KubernetesWatchGenerator
|
||||
{
|
||||
class Program
|
||||
internal class Program
|
||||
{
|
||||
private static HashSet<string> _classesWithValidation;
|
||||
static readonly Dictionary<string, string> ClassNameMap = new Dictionary<string, string>();
|
||||
private static readonly Dictionary<string, string> ClassNameMap = new Dictionary<string, string>();
|
||||
private static Dictionary<JsonSchema4, string> _schemaToNameMap;
|
||||
private static HashSet<string> _schemaDefinitionsInMultipleGroups;
|
||||
private static Dictionary<string, string> _classNameToPluralMap;
|
||||
|
||||
static async Task Main(string[] args)
|
||||
private static async Task Main(string[] args)
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
@@ -31,7 +31,7 @@ namespace KubernetesWatchGenerator
|
||||
|
||||
// Read the spec trimmed
|
||||
// here we cache all name in gen project for later use
|
||||
var swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json"));
|
||||
var swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json")).ConfigureAwait(false);
|
||||
foreach (var (k, v) in swagger.Definitions)
|
||||
{
|
||||
if (v.ExtensionData?.TryGetValue("x-kubernetes-group-version-kind", out var _) == true)
|
||||
@@ -46,9 +46,8 @@ namespace KubernetesWatchGenerator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// gen project removed all watch operations, so here we switch back to unprocessed version
|
||||
swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json.unprocessed"));
|
||||
swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json.unprocessed")).ConfigureAwait(false);
|
||||
_schemaToNameMap = swagger.Definitions.ToDictionary(x => x.Value, x => x.Key);
|
||||
_schemaDefinitionsInMultipleGroups = _schemaToNameMap.Values.Select(x =>
|
||||
{
|
||||
@@ -90,7 +89,6 @@ namespace KubernetesWatchGenerator
|
||||
.Union(_classNameToPluralMap)
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
|
||||
// Register helpers used in the templating.
|
||||
Helpers.Register(nameof(ToXmlDoc), ToXmlDoc);
|
||||
Helpers.Register(nameof(GetClassName), GetClassName);
|
||||
@@ -166,12 +164,9 @@ namespace KubernetesWatchGenerator
|
||||
|
||||
Render.FileToFile("VersionConverter.cs.template", versionConverterPairs, Path.Combine(outputDirectory, "VersionConverter.cs"));
|
||||
Render.FileToFile("ModelOperators.cs.template", typePairs, Path.Combine(outputDirectory, "ModelOperators.cs"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void ToXmlDoc(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void ToXmlDoc(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is string)
|
||||
@@ -199,7 +194,7 @@ namespace KubernetesWatchGenerator
|
||||
}
|
||||
}
|
||||
|
||||
static void GetTuple(RenderContext context, IList<object> arguments, IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
|
||||
private static void GetTuple(RenderContext context, IList<object> arguments, IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] is ITuple && options.TryGetValue("index", out var indexObj) && int.TryParse(indexObj?.ToString(), out var index))
|
||||
{
|
||||
@@ -209,9 +204,7 @@ namespace KubernetesWatchGenerator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void GetClassName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetClassName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerOperation)
|
||||
@@ -224,7 +217,7 @@ namespace KubernetesWatchGenerator
|
||||
}
|
||||
}
|
||||
|
||||
static string GetClassName(SwaggerOperation watchOperation)
|
||||
private static string GetClassName(SwaggerOperation watchOperation)
|
||||
{
|
||||
var groupVersionKind =
|
||||
(Dictionary<string, object>)watchOperation.ExtensionData["x-kubernetes-group-version-kind"];
|
||||
@@ -257,7 +250,7 @@ namespace KubernetesWatchGenerator
|
||||
}
|
||||
}
|
||||
|
||||
static string GetClassNameForSchemaDefinition(JsonSchema4 definition)
|
||||
private static string GetClassNameForSchemaDefinition(JsonSchema4 definition)
|
||||
{
|
||||
if (definition.ExtensionData != null &&
|
||||
definition.ExtensionData.ContainsKey("x-kubernetes-group-version-kind"))
|
||||
@@ -280,7 +273,7 @@ namespace KubernetesWatchGenerator
|
||||
return className;
|
||||
}
|
||||
|
||||
static string GetInterfaceName(JsonSchema4 definition)
|
||||
private static string GetInterfaceName(JsonSchema4 definition)
|
||||
{
|
||||
var groupVersionKindElements = (object[])definition.ExtensionData["x-kubernetes-group-version-kind"];
|
||||
var groupVersionKind = (Dictionary<string, object>)groupVersionKindElements[0];
|
||||
@@ -321,8 +314,7 @@ namespace KubernetesWatchGenerator
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void GetKind(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetKind(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4)
|
||||
@@ -339,7 +331,7 @@ namespace KubernetesWatchGenerator
|
||||
return groupVersionKind["kind"] as string;
|
||||
}
|
||||
|
||||
static void GetPlural(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetPlural(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4)
|
||||
@@ -362,7 +354,7 @@ namespace KubernetesWatchGenerator
|
||||
return _classNameToPluralMap.GetValueOrDefault(className, null);
|
||||
}
|
||||
|
||||
static void GetGroup(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetGroup(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4)
|
||||
@@ -379,7 +371,7 @@ namespace KubernetesWatchGenerator
|
||||
return groupVersionKind["group"] as string;
|
||||
}
|
||||
|
||||
static void GetMethodName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetMethodName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerOperation)
|
||||
@@ -388,8 +380,7 @@ namespace KubernetesWatchGenerator
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static string GetMethodName(SwaggerOperation watchOperation)
|
||||
private static string GetMethodName(SwaggerOperation watchOperation)
|
||||
{
|
||||
var tag = watchOperation.Tags[0];
|
||||
tag = tag.Replace("_", string.Empty);
|
||||
@@ -402,7 +393,7 @@ namespace KubernetesWatchGenerator
|
||||
return methodName;
|
||||
}
|
||||
|
||||
static void GetDotNetType(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetDotNetType(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerParameter)
|
||||
@@ -463,7 +454,7 @@ namespace KubernetesWatchGenerator
|
||||
}
|
||||
}
|
||||
|
||||
static void GetDotNetName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetDotNetName(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerParameter)
|
||||
@@ -492,7 +483,7 @@ namespace KubernetesWatchGenerator
|
||||
return jsonName;
|
||||
}
|
||||
|
||||
static void GetPathExpression(RenderContext context, IList<object> arguments,
|
||||
private static void GetPathExpression(RenderContext context, IList<object> arguments,
|
||||
IDictionary<string, object> options, RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null &&
|
||||
@@ -516,7 +507,7 @@ namespace KubernetesWatchGenerator
|
||||
return pathExpression;
|
||||
}
|
||||
|
||||
static void GetApiVersion(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
private static void GetApiVersion(RenderContext context, IList<object> arguments, IDictionary<string, object> options,
|
||||
RenderBlock fn, RenderBlock inverse)
|
||||
{
|
||||
if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4)
|
||||
|
||||
@@ -1,13 +1,297 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RuleSet Name="kubernetes-client" ToolsVersion="10.0">
|
||||
|
||||
<!-- style guideline https://github.com/kubernetes-client/csharp/issues/439 -->
|
||||
|
||||
<!-- https://github.com/DotNetAnalyzers/StyleCopAnalyzers/tree/master/documentation -->
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
|
||||
<Rule Id="SA1027" Action="Error" />
|
||||
|
||||
<Rule Id="SA1101" Action="None" />
|
||||
<!-- The file name of a C# code file does not match the first type declared in the file. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1649.md -->
|
||||
<Rule Id="SA1649" Action="Error" />
|
||||
|
||||
<!-- A C# code element is missing a documentation header. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1600.md -->
|
||||
<Rule Id="SA1600" Action="None" />
|
||||
|
||||
<!-- A C# partial element is missing a documentation header. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1601.md -->
|
||||
<Rule Id="SA1601" Action="None" />
|
||||
|
||||
<!-- An item within a C# enumeration is missing an Xml documentation header. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1602.md -->
|
||||
<Rule Id="SA1602" Action="Warning" />
|
||||
|
||||
<!-- A C# method, constructor, delegate or indexer element is missing documentation for one or more of its parameters. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1611.md -->
|
||||
<Rule Id="SA1611" Action="Warning" />
|
||||
|
||||
<!-- The documentation describing the parameters to a C# method, constructor, delegate or indexer element does not match the actual parameters on the element. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1612.md -->
|
||||
<Rule Id="SA1612" Action="Warning" />
|
||||
|
||||
<!-- A C# element is missing documentation for its return value. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1615.md -->
|
||||
<Rule Id="SA1615" Action="Warning" />
|
||||
|
||||
<!-- A generic C# element is missing documentation for one or more of its generic type parameters. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1618.md -->
|
||||
<Rule Id="SA1618" Action="Warning" />
|
||||
|
||||
<!-- A `<typeparam>` tag within the Xml header documentation for a generic C# element is empty. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1622.md -->
|
||||
<Rule Id="SA1622" Action="Warning" />
|
||||
|
||||
<!-- The documentation text within a C# property's `<summary>` tag does not match the accessors within the property. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1623.md -->
|
||||
<Rule Id="SA1623" Action="None" />
|
||||
|
||||
<!-- The Xml documentation for a C# element contains two or more identical entries, indicating that the documentation has been copied and pasted. This can sometimes indicate invalid or poorly written documentation. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1625.md -->
|
||||
<Rule Id="SA1625" Action="Warning" />
|
||||
|
||||
<!-- A section of the Xml header documentation for a C# element does not end with a period (also known as a full stop). https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1629.md -->
|
||||
<Rule Id="SA1629" Action="None" />
|
||||
|
||||
<!-- A C# code file is missing a standard file header. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1633.md -->
|
||||
<Rule Id="SA1633" Action="None" />
|
||||
|
||||
<!-- The XML documentation header for a C# constructor does not contain the appropriate summary text. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1642.md -->
|
||||
<Rule Id="SA1642" Action="Warning" />
|
||||
|
||||
<!-- The opening or closing brace within a C# statement, element, or expression is not placed on its own line. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1500.md -->
|
||||
<Rule Id="SA1500" Action="Error" />
|
||||
|
||||
<!-- The opening and closing braces for a C# statement have been omitted. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1503.md -->
|
||||
<Rule Id="SA1500" Action="Error" />
|
||||
|
||||
<!-- The C# code contains multiple blank lines in a row. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md -->
|
||||
<Rule Id="SA1507" Action="None" />
|
||||
|
||||
<!-- An opening brace within a C# element, statement, or expression is preceded by a blank line. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1509.md -->
|
||||
<Rule Id="SA1509" Action="Warning" />
|
||||
|
||||
<!-- A single-line comment within C# code is followed by a blank line. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md -->
|
||||
<Rule Id="SA1512" Action="None" />
|
||||
|
||||
<!-- A closing brace within a C# element, statement, or expression is not followed by a blank line. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1513.md -->
|
||||
<Rule Id="SA1513" Action="Error" />
|
||||
|
||||
<!-- A single-line comment within C# code is not preceded by a blank line. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1515.md -->
|
||||
<Rule Id="SA1515" Action="None" />
|
||||
|
||||
<!-- Adjacent C# elements are not separated by a blank line. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1516.md -->
|
||||
<Rule Id="SA1516" Action="None" />
|
||||
|
||||
<!-- A C# statement contains parenthesis which are unnecessary and should be removed. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1119.md -->
|
||||
<Rule Id="SA1119" Action="None" />
|
||||
|
||||
<!-- The access modifier for a C# element has not been explicitly defined. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1400.md -->
|
||||
<Rule Id="SA1400" Action="Error" />
|
||||
|
||||
<!-- A field within a C# class has an access modifier other than private. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md -->
|
||||
<Rule Id="SA1401" Action="Error" />
|
||||
|
||||
<!-- A C# code file contains more than one unique type. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1402.md -->
|
||||
<Rule Id="SA1402" Action="Error" />
|
||||
|
||||
<!-- A call to Debug.Assert in C# code does not include a descriptive message. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1405.md -->
|
||||
<Rule Id="SA1405" Action="Warning" />
|
||||
|
||||
<!-- The last statement in a multi-line C# initializer or list is missing a trailing comma. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1413.md -->
|
||||
<Rule Id="SA1413" Action="Error" />
|
||||
|
||||
<!-- The name of a C# element does not begin with an upper-case letter. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md -->
|
||||
<Rule Id="SA1300" Action="None" />
|
||||
|
||||
<!-- The name of a field in C# does not begin with a lower-case letter. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md -->
|
||||
<Rule Id="SA1306" Action="Error" />
|
||||
|
||||
<!-- A field name in C# begins with an underscore. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1309.md -->
|
||||
<Rule Id="SA1309" Action="None" />
|
||||
|
||||
<Rule Id="SA1503" Action="Error" />
|
||||
<!-- The name of a variable in C# does not begin with a lower-case letter. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md -->
|
||||
<Rule Id="SA1312" Action="Error" />
|
||||
|
||||
<!-- The name of a C# type parameter does not begin with the capital letter T. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1314.md -->
|
||||
<Rule Id="SA1314" Action="None" />
|
||||
|
||||
<!-- A C# using directive is placed outside of a namespace element. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1200.md -->
|
||||
<Rule Id="SA1200" Action="Warning" />
|
||||
|
||||
<!-- An element within a C# code file is out of order in relation to the other elements in the code. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1201.md -->
|
||||
<Rule Id="SA1201" Action="None" />
|
||||
|
||||
<!-- An element within a C# code file is out of order within regard to access level, in relation to other elements in the code. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1202.md -->
|
||||
<Rule Id="SA1202" Action="None" />
|
||||
|
||||
<!-- A constant field is placed beneath a non-constant field. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1203.md -->
|
||||
<Rule Id="SA1203" Action="None" />
|
||||
|
||||
<!-- A static element is positioned beneath an instance element of the same type. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1204.md -->
|
||||
<Rule Id="SA1204" Action="None" />
|
||||
|
||||
<!-- The keywords within the declaration of an element do not follow a standard ordering scheme. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1206.md -->
|
||||
<Rule Id="SA1206" Action="None" />
|
||||
|
||||
<!-- The using directives within a C# code file are not sorted alphabetically by namespace. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1210.md -->
|
||||
<Rule Id="SA1210" Action="None" />
|
||||
|
||||
<!-- A readonly field is positioned beneath a non-readonly field. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1214.md -->
|
||||
<Rule Id="SA1214" Action="None" />
|
||||
|
||||
<!-- A call to an instance member of the local class or a base class is not prefixed with 'this.', within a C# code file. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1101.md -->
|
||||
<Rule Id="SA1101" Action="None" />
|
||||
|
||||
<!-- A C# statement contains a comment between the declaration of the statement and the opening brace of the statement. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1108.md -->
|
||||
<Rule Id="SA1108" Action="Error" />
|
||||
|
||||
<!-- A comma between two parameters in a call to a C# method or indexer, or in the declaration of a method or indexer, is not placed on the same line as the previous parameter. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1113.md -->
|
||||
<Rule Id="SA1113" Action="Warning" />
|
||||
|
||||
<!-- The parameters to a C# method or indexer call or declaration span across multiple lines, but the first parameter does not start on the line after the opening bracket. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1116.md -->
|
||||
<Rule Id="SA1116" Action="Warning" />
|
||||
|
||||
<!-- The parameters to a C# method or indexer call or declaration are not all on the same line or each on a separate line. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1117.md -->
|
||||
<Rule Id="SA1117" Action="None" />
|
||||
|
||||
<!-- A parameter to a C# method or indexer, other than the first parameter, spans across multiple lines. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1118.md -->
|
||||
<Rule Id="SA1118" Action="Warning" />
|
||||
|
||||
<!-- The C# comment does not contain any comment text. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1120.md -->
|
||||
<Rule Id="SA1120" Action="None" />
|
||||
|
||||
<!-- The code uses one of the basic C# types, but does not use the built-in alias for the type. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1121.md -->
|
||||
<Rule Id="SA1121" Action="Warning" />
|
||||
|
||||
<!-- The C# code includes an empty string, written as `""`. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1122.md -->
|
||||
<Rule Id="SA1122" Action="None" />
|
||||
|
||||
<!-- The C# code contains a region. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1124.md -->
|
||||
<Rule Id="SA1124" Action="Error" />
|
||||
|
||||
<!-- A generic constraint on a type or method declaration is on the same line as the declaration, within a C# code file. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1127.md -->
|
||||
<Rule Id="SA1127" Action="Warning" />
|
||||
|
||||
<!-- A constructor initializer is on the same line as the constructor declaration, within a C# code file. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1128.md -->
|
||||
<Rule Id="SA1128" Action="Warning" />
|
||||
|
||||
<!-- A comparison was made between a variable and a literal or constant value, and the variable appeared on the right-hand side of the expression. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1131.md -->
|
||||
<Rule Id="SA1131" Action="Error" />
|
||||
|
||||
<!-- An attribute is placed on the same line of code as another attribute or element. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1134.md -->
|
||||
<Rule Id="SA1134" Action="Warning" />
|
||||
|
||||
<!-- The spacing around a comma is incorrect, within a C# code file. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1001.md -->
|
||||
<Rule Id="SA1001" Action="Warning" />
|
||||
|
||||
<!-- A closing parenthesis within a C# statement is not spaced correctly. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1009.md -->
|
||||
<Rule Id="SA1009" Action="Warning" />
|
||||
|
||||
<!-- An opening brace within a C# element is not spaced correctly. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1012.md -->
|
||||
<Rule Id="SA1012" Action="Warning" />
|
||||
|
||||
<!-- The code contains a tab or space character which is not consistent with the current project settings. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1027.md -->
|
||||
<Rule Id="SA1027" Action="Error" />
|
||||
|
||||
<!-- A line of code ends with a space, tab, or other whitespace characters before the end of line character(s). https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1028.md -->
|
||||
<Rule Id="SA1028" Action="Warning" />
|
||||
|
||||
<!-- All diagnostics of XML documentation comments has been disabled due to the current project configuration. https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA0001.md -->
|
||||
<Rule Id="SA0001" Action="Warning" />
|
||||
|
||||
<!-- Call GC.SuppressFinalize correctly https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1816 -->
|
||||
<Rule Id="CA1816" Action="Error" />
|
||||
|
||||
<!-- Review unused parameters https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1801 -->
|
||||
<Rule Id="CA1801" Action="None" />
|
||||
|
||||
<!-- Rethrow to preserve stack details https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2200 -->
|
||||
<Rule Id="CA2200" Action="Warning" />
|
||||
|
||||
<!-- Disposable fields should be disposed https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2213 -->
|
||||
<Rule Id="CA2213" Action="Warning" />
|
||||
|
||||
<!-- Operator overloads have named alternates https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2225 -->
|
||||
<Rule Id="CA2225" Action="None" />
|
||||
|
||||
<!-- Collection properties should be read only https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2227 -->
|
||||
<Rule Id="CA2227" Action="Warning" />
|
||||
|
||||
<!-- Mark ISerializable types with SerializableAttribute https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2237 -->
|
||||
<Rule Id="CA2237" Action="Warning" />
|
||||
|
||||
<!-- Do Not Disable Certificate Validation https://docs.microsoft.com/en-us/visualstudio/code-quality/CA5359 -->
|
||||
<Rule Id="CA5359" Action="None" />
|
||||
|
||||
<!-- Mark attributes with AttributeUsageAttribute https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1018 -->
|
||||
<Rule Id="CA1018" Action="Warning" />
|
||||
|
||||
<!-- Enum storage should be Int32 https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1028 -->
|
||||
<Rule Id="CA1028" Action="Warning" />
|
||||
|
||||
<!-- Do not catch general exception types https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1031 -->
|
||||
<Rule Id="CA1031" Action="Warning" />
|
||||
|
||||
<!-- Nested types should not be visible https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1034 -->
|
||||
<Rule Id="CA1034" Action="Warning" />
|
||||
|
||||
<!-- Do not declare visible instance fields https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1051 -->
|
||||
<Rule Id="CA1051" Action="Warning" />
|
||||
|
||||
<!-- Static holder types should be Static or NotInheritable https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1052 -->
|
||||
<Rule Id="CA1052" Action="None" />
|
||||
|
||||
<!-- URI parameters should not be strings https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1054 -->
|
||||
<Rule Id="CA1054" Action="None" />
|
||||
|
||||
<!-- Validate arguments of public methods https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1062 -->
|
||||
<Rule Id="CA1062" Action="Warning" />
|
||||
|
||||
<!-- Implement IDisposable correctly https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1063 -->
|
||||
<Rule Id="CA1063" Action="Error" />
|
||||
|
||||
<!-- Do not pass literals as localized parameters https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1303 -->
|
||||
<Rule Id="CA1303" Action="None" />
|
||||
|
||||
<!-- Specify CultureInfo https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1304 -->
|
||||
<Rule Id="CA1304" Action="None" />
|
||||
|
||||
<!-- Specify IFormatProvider https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1305 -->
|
||||
<Rule Id="CA1305" Action="None" />
|
||||
|
||||
<!-- Specify StringComparison https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1307 -->
|
||||
<Rule Id="CA1307" Action="None" />
|
||||
|
||||
<!-- Normalize strings to uppercase https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1308 -->
|
||||
<Rule Id="CA1308" Action="None" />
|
||||
|
||||
<!-- Identifiers should not contain underscores https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1707 -->
|
||||
<Rule Id="CA1707" Action="Error" />
|
||||
|
||||
<!-- Identifiers should have correct prefix https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1715 -->
|
||||
<Rule Id="CA1715" Action="None" />
|
||||
|
||||
<!-- Identifiers should not match keywords https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1716 -->
|
||||
<Rule Id="CA1716" Action="None" />
|
||||
|
||||
<!-- Identifiers should not contain type names https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1720 -->
|
||||
<Rule Id="CA1720" Action="None" />
|
||||
|
||||
<!-- Use Literals Where Appropriate https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1802 -->
|
||||
<Rule Id="CA1802" Action="Error" />
|
||||
|
||||
<!-- Avoid uninstantiated internal classes https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1812 -->
|
||||
<Rule Id="CA1812" Action="Error" />
|
||||
|
||||
<!-- Mark members as static https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1822 -->
|
||||
<Rule Id="CA1822" Action="None" />
|
||||
|
||||
<!-- Avoid zero-length array allocations https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1825 -->
|
||||
<Rule Id="CA1825" Action="None" />
|
||||
|
||||
<!-- Do not use Count/LongCount when Any can be used https://docs.microsoft.com/en-us/visualstudio/code-quality/CA1827 -->
|
||||
<Rule Id="CA1827" Action="Error" />
|
||||
|
||||
<!-- Dispose objects before losing scope https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2000 -->
|
||||
<!-- TODO -->
|
||||
<Rule Id="CA2000" Action="None" />
|
||||
|
||||
<!-- Do not directly await a Task https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2007 -->
|
||||
<Rule Id="CA2007" Action="Error" />
|
||||
|
||||
<!-- Do not create tasks without passing a TaskScheduler https://docs.microsoft.com/en-us/visualstudio/code-quality/CA2008 -->
|
||||
<!-- TODO -->
|
||||
<Rule Id="CA2008" Action="None" />
|
||||
|
||||
</Rules>
|
||||
</RuleSet>
|
||||
|
||||
@@ -24,8 +24,9 @@ namespace k8s.Authentication
|
||||
{
|
||||
if (DateTime.UtcNow.AddSeconds(30) > _expiry)
|
||||
{
|
||||
await RefreshToken();
|
||||
await RefreshToken().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return new AuthenticationHeaderValue("Bearer", _token);
|
||||
}
|
||||
|
||||
@@ -40,9 +41,9 @@ namespace k8s.Authentication
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
RedirectStandardError = true,
|
||||
},
|
||||
EnableRaisingEvents = true
|
||||
EnableRaisingEvents = true,
|
||||
};
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
process.Exited += (sender, arg) =>
|
||||
@@ -53,14 +54,14 @@ namespace k8s.Authentication
|
||||
var output = process.StandardOutput.ReadToEndAsync();
|
||||
var err = process.StandardError.ReadToEndAsync();
|
||||
|
||||
await Task.WhenAll(tcs.Task, output, err);
|
||||
await Task.WhenAll(tcs.Task, output, err).ConfigureAwait(false);
|
||||
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
throw new KubernetesClientException($"Unable to obtain a token via gcloud command. Error code {process.ExitCode}. \n {err}");
|
||||
}
|
||||
|
||||
var json = JToken.Parse(await output);
|
||||
var json = JToken.Parse(await output.ConfigureAwait(false));
|
||||
_token = json["credential"]["access_token"].Value<string>();
|
||||
_expiry = json["credential"]["token_expiry"].Value<DateTime>();
|
||||
}
|
||||
|
||||
@@ -9,29 +9,30 @@ namespace k8s.Authentication
|
||||
{
|
||||
public class TokenFileAuth : ITokenProvider
|
||||
{
|
||||
private string _token;
|
||||
internal string _token_file { get; set; }
|
||||
internal DateTime _token_expires_at { get; set; }
|
||||
private string token;
|
||||
internal string TokenFile { get; set; }
|
||||
internal DateTime TokenExpiresAt { get; set; }
|
||||
|
||||
public TokenFileAuth(string token_file)
|
||||
public TokenFileAuth(string tokenFile)
|
||||
{
|
||||
_token_file = token_file;
|
||||
TokenFile = tokenFile;
|
||||
}
|
||||
|
||||
public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_token_expires_at < DateTime.UtcNow)
|
||||
if (TokenExpiresAt < DateTime.UtcNow)
|
||||
{
|
||||
_token = File.ReadAllText(_token_file).Trim();
|
||||
token = File.ReadAllText(TokenFile).Trim();
|
||||
// in fact, the token has a expiry of 10 minutes and kubelet
|
||||
// refreshes it at 8 minutes of its lifetime. setting the expiry
|
||||
// of 1 minute makes sure the token is reloaded regularly so
|
||||
// that its actual expiry is after the declared expiry here,
|
||||
// which is as suffciently true as the time of reading a token
|
||||
// < 10-8-1 minute.
|
||||
_token_expires_at = DateTime.UtcNow.AddMinutes(1);
|
||||
TokenExpiresAt = DateTime.UtcNow.AddMinutes(1);
|
||||
}
|
||||
return new AuthenticationHeaderValue("Bearer", _token);
|
||||
|
||||
return new AuthenticationHeaderValue("Bearer", token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace k8s
|
||||
/// more data is available.
|
||||
/// </summary>
|
||||
private bool endOfFile;
|
||||
private bool disposedValue;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ByteBuffer"/> class using the default buffer size and limit.
|
||||
@@ -145,12 +146,6 @@ namespace k8s
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(this.buffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes bytes to the buffer.
|
||||
/// </summary>
|
||||
@@ -307,5 +302,34 @@ namespace k8s
|
||||
Debug.Assert(this.bytesRead + this.AvailableReadableBytes == this.bytesWritten);
|
||||
this.OnResize?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(this.buffer);
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~ByteBuffer()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace k8s
|
||||
/// pod.
|
||||
/// </summary>
|
||||
/// <seealso href="https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/server/remotecommand/websocket.go#L29"/>
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1028:Enum Storage should be Int32", Justification = "byte only")]
|
||||
public enum ChannelIndex : byte
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -16,7 +16,6 @@ namespace k8s
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
|
||||
public static KubernetesEntityAttribute GetKubernetesTypeMetadata<T>(this T obj) where T : IKubernetesObject =>
|
||||
obj.GetType().GetKubernetesTypeMetadata();
|
||||
public static KubernetesEntityAttribute GetKubernetesTypeMetadata(this Type currentType)
|
||||
@@ -26,6 +25,7 @@ namespace k8s
|
||||
{
|
||||
throw new InvalidOperationException($"Custom resource must have {nameof(KubernetesEntityAttribute)} applied to it");
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,5 @@ namespace k8s
|
||||
}
|
||||
|
||||
internal static bool IsValidKubernetesName(this string value) => !Regex.IsMatch(value, "^[a-z0-9-]+$");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
32
src/KubernetesClient/IntOrStringConverter.cs
Normal file
32
src/KubernetesClient/IntOrStringConverter.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
internal class IntOrStringConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var s = (value as IntstrIntOrString)?.Value;
|
||||
|
||||
if (int.TryParse(s, out var intv))
|
||||
{
|
||||
serializer.Serialize(writer, intv);
|
||||
return;
|
||||
}
|
||||
|
||||
serializer.Serialize(writer, s);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
return (IntstrIntOrString)serializer.Deserialize<string>(reader);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(int) || objectType == typeof(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/KubernetesClient/IntOrStringYamlConverter.cs
Normal file
42
src/KubernetesClient/IntOrStringYamlConverter.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
public class IntOrStringYamlConverter : IYamlTypeConverter
|
||||
{
|
||||
public bool Accepts(Type type)
|
||||
{
|
||||
return type == typeof(IntstrIntOrString);
|
||||
}
|
||||
|
||||
public object ReadYaml(IParser parser, Type type)
|
||||
{
|
||||
if (parser.Current is YamlDotNet.Core.Events.Scalar scalar)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(scalar.Value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IntstrIntOrString(scalar.Value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(parser.Current?.ToString());
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object value, Type type)
|
||||
{
|
||||
var obj = (IntstrIntOrString)value;
|
||||
emitter.Emit(new YamlDotNet.Core.Events.Scalar(obj.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +1,10 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Core.Tokens;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
public class IntOrStringYamlConverter : IYamlTypeConverter
|
||||
{
|
||||
public bool Accepts(Type type)
|
||||
{
|
||||
return type == typeof(IntstrIntOrString);
|
||||
}
|
||||
|
||||
public object ReadYaml(IParser parser, Type type)
|
||||
{
|
||||
if (parser.Current is YamlDotNet.Core.Events.Scalar scalar)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(scalar.Value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new IntstrIntOrString(scalar.Value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
parser.MoveNext();
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException(parser.Current?.ToString());
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object value, Type type)
|
||||
{
|
||||
var obj = (IntstrIntOrString)value;
|
||||
emitter.Emit(new YamlDotNet.Core.Events.Scalar(obj.Value));
|
||||
}
|
||||
}
|
||||
|
||||
internal class IntOrStringConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var s = (value as IntstrIntOrString)?.Value;
|
||||
|
||||
if (int.TryParse(s, out var intv))
|
||||
{
|
||||
serializer.Serialize(writer, intv);
|
||||
return;
|
||||
}
|
||||
|
||||
serializer.Serialize(writer, s);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
return (IntstrIntOrString)serializer.Deserialize<string>(reader);
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(int) || objectType == typeof(string);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(IntOrStringConverter))]
|
||||
public partial class IntstrIntOrString
|
||||
{
|
||||
@@ -120,7 +55,7 @@ namespace k8s.Models
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return (Value != null ? Value.GetHashCode() : 0);
|
||||
return Value != null ? Value.GetHashCode() : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,6 +306,7 @@ namespace k8s
|
||||
{
|
||||
throw new ArgumentNullException(nameof(config));
|
||||
}
|
||||
|
||||
if (config.TokenProvider != null)
|
||||
{
|
||||
return new TokenCredentials(config.TokenProvider);
|
||||
|
||||
@@ -21,11 +21,11 @@ namespace k8s
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// Tracing
|
||||
bool _shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string _invocationId = null;
|
||||
if (_shouldTrace)
|
||||
bool shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string invocationId = null;
|
||||
if (shouldTrace)
|
||||
{
|
||||
_invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
Dictionary<string, object> tracingParameters = new Dictionary<string, object>();
|
||||
tracingParameters.Add("path", path);
|
||||
tracingParameters.Add("continue", @continue);
|
||||
@@ -36,7 +36,7 @@ namespace k8s
|
||||
tracingParameters.Add("pretty", pretty);
|
||||
tracingParameters.Add("timeoutSeconds", timeoutSeconds);
|
||||
tracingParameters.Add("resourceVersion", resourceVersion);
|
||||
ServiceClientTracing.Enter(_invocationId, this, nameof(WatchObjectAsync), tracingParameters);
|
||||
ServiceClientTracing.Enter(invocationId, this, nameof(WatchObjectAsync), tracingParameters);
|
||||
}
|
||||
|
||||
// Construct URL
|
||||
@@ -124,9 +124,9 @@ namespace k8s
|
||||
}
|
||||
|
||||
// Send Request
|
||||
if (_shouldTrace)
|
||||
if (shouldTrace)
|
||||
{
|
||||
ServiceClientTracing.SendRequest(_invocationId, httpRequest);
|
||||
ServiceClientTracing.SendRequest(invocationId, httpRequest);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
@@ -134,9 +134,9 @@ namespace k8s
|
||||
.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (_shouldTrace)
|
||||
if (shouldTrace)
|
||||
{
|
||||
ServiceClientTracing.ReceiveResponse(_invocationId, httpResponse);
|
||||
ServiceClientTracing.ReceiveResponse(invocationId, httpResponse);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -90,11 +90,11 @@ namespace k8s
|
||||
}
|
||||
|
||||
// Tracing
|
||||
bool _shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string _invocationId = null;
|
||||
if (_shouldTrace)
|
||||
bool shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string invocationId = null;
|
||||
if (shouldTrace)
|
||||
{
|
||||
_invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
Dictionary<string, object> tracingParameters = new Dictionary<string, object>();
|
||||
tracingParameters.Add("command", command);
|
||||
tracingParameters.Add("container", container);
|
||||
@@ -106,7 +106,7 @@ namespace k8s
|
||||
tracingParameters.Add("tty", tty);
|
||||
tracingParameters.Add("webSocketSubProtol", webSocketSubProtol);
|
||||
tracingParameters.Add("cancellationToken", cancellationToken);
|
||||
ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodExecAsync),
|
||||
ServiceClientTracing.Enter(invocationId, this, nameof(WebSocketNamespacedPodExecAsync),
|
||||
tracingParameters);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace k8s
|
||||
uriBuilder.Query =
|
||||
query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it
|
||||
|
||||
return this.StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtol, customHeaders,
|
||||
return this.StreamConnectAsync(uriBuilder.Uri, invocationId, webSocketSubProtol, customHeaders,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
@@ -169,18 +169,18 @@ namespace k8s
|
||||
}
|
||||
|
||||
// Tracing
|
||||
bool _shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string _invocationId = null;
|
||||
if (_shouldTrace)
|
||||
bool shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string invocationId = null;
|
||||
if (shouldTrace)
|
||||
{
|
||||
_invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
Dictionary<string, object> tracingParameters = new Dictionary<string, object>();
|
||||
tracingParameters.Add("name", name);
|
||||
tracingParameters.Add("@namespace", @namespace);
|
||||
tracingParameters.Add("ports", ports);
|
||||
tracingParameters.Add("webSocketSubProtocol", webSocketSubProtocol);
|
||||
tracingParameters.Add("cancellationToken", cancellationToken);
|
||||
ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodPortForwardAsync),
|
||||
ServiceClientTracing.Enter(invocationId, this, nameof(WebSocketNamespacedPodPortForwardAsync),
|
||||
tracingParameters);
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ namespace k8s
|
||||
|
||||
uriBuilder.Query = q.ToString();
|
||||
|
||||
return StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtocol, customHeaders,
|
||||
return StreamConnectAsync(uriBuilder.Uri, invocationId, webSocketSubProtocol, customHeaders,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
@@ -229,11 +229,11 @@ namespace k8s
|
||||
}
|
||||
|
||||
// Tracing
|
||||
bool _shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string _invocationId = null;
|
||||
if (_shouldTrace)
|
||||
bool shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
string invocationId = null;
|
||||
if (shouldTrace)
|
||||
{
|
||||
_invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
invocationId = ServiceClientTracing.NextInvocationId.ToString();
|
||||
Dictionary<string, object> tracingParameters = new Dictionary<string, object>();
|
||||
tracingParameters.Add("container", container);
|
||||
tracingParameters.Add("name", name);
|
||||
@@ -244,7 +244,7 @@ namespace k8s
|
||||
tracingParameters.Add("tty", tty);
|
||||
tracingParameters.Add("webSocketSubProtol", webSocketSubProtol);
|
||||
tracingParameters.Add("cancellationToken", cancellationToken);
|
||||
ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodAttachAsync),
|
||||
ServiceClientTracing.Enter(invocationId, this, nameof(WebSocketNamespacedPodAttachAsync),
|
||||
tracingParameters);
|
||||
}
|
||||
|
||||
@@ -268,7 +268,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, _invocationId, webSocketSubProtol, customHeaders,
|
||||
return StreamConnectAsync(uriBuilder.Uri, invocationId, webSocketSubProtol, customHeaders,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace k8s
|
||||
string webSocketSubProtocol = null, Dictionary<string, List<string>> customHeaders = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
bool _shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
bool shouldTrace = ServiceClientTracing.IsEnabled;
|
||||
|
||||
// Create WebSocket transport objects
|
||||
WebSocketBuilder webSocketBuilder = this.CreateWebSocketBuilder();
|
||||
@@ -284,9 +284,9 @@ namespace k8s
|
||||
// Set Headers
|
||||
if (customHeaders != null)
|
||||
{
|
||||
foreach (var _header in customHeaders)
|
||||
foreach (var header in customHeaders)
|
||||
{
|
||||
webSocketBuilder.SetRequestHeader(_header.Key, string.Join(" ", _header.Value));
|
||||
webSocketBuilder.SetRequestHeader(header.Key, string.Join(" ", header.Value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,9 +306,9 @@ namespace k8s
|
||||
HttpRequestMessage message = new HttpRequestMessage();
|
||||
await this.Credentials.ProcessHttpRequestAsync(message, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
foreach (var _header in message.Headers)
|
||||
foreach (var header in message.Headers)
|
||||
{
|
||||
webSocketBuilder.SetRequestHeader(_header.Key, string.Join(" ", _header.Value));
|
||||
webSocketBuilder.SetRequestHeader(header.Key, string.Join(" ", header.Value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,8 +347,8 @@ namespace k8s
|
||||
}
|
||||
catch (WebSocketException wse) when (wse.WebSocketErrorCode == WebSocketError.HeaderError ||
|
||||
(wse.InnerException is WebSocketException &&
|
||||
((WebSocketException)wse.InnerException).WebSocketErrorCode ==
|
||||
WebSocketError.HeaderError))
|
||||
((WebSocketException)wse.InnerException).WebSocketErrorCode ==
|
||||
WebSocketError.HeaderError))
|
||||
{
|
||||
// This usually indicates the server sent an error message, like 400 Bad Request. Unfortunately, the WebSocket client
|
||||
// class doesn't give us a lot of information about what went wrong. So, retry the connection.
|
||||
@@ -392,7 +392,7 @@ namespace k8s
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (_shouldTrace)
|
||||
if (shouldTrace)
|
||||
{
|
||||
ServiceClientTracing.Error(invocationId, ex);
|
||||
}
|
||||
@@ -401,7 +401,7 @@ namespace k8s
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (_shouldTrace)
|
||||
if (shouldTrace)
|
||||
{
|
||||
ServiceClientTracing.Exit(invocationId, null);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ using k8s.Authentication;
|
||||
using k8s.Exceptions;
|
||||
using k8s.KubeConfigModels;
|
||||
|
||||
|
||||
namespace k8s
|
||||
{
|
||||
public partial class KubernetesClientConfiguration
|
||||
@@ -334,7 +333,7 @@ namespace k8s
|
||||
var config = userDetails.UserCredentials.AuthProvider.Config;
|
||||
if (config.ContainsKey("expires-on"))
|
||||
{
|
||||
var expiresOn = Int32.Parse(config["expires-on"]);
|
||||
var expiresOn = int.Parse(config["expires-on"]);
|
||||
DateTimeOffset expires;
|
||||
#if NET452
|
||||
var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
@@ -344,18 +343,18 @@ namespace k8s
|
||||
expires = DateTimeOffset.FromUnixTimeSeconds(expiresOn);
|
||||
#endif
|
||||
|
||||
if (DateTimeOffset.Compare(expires
|
||||
, DateTimeOffset.Now)
|
||||
if (DateTimeOffset.Compare(expires,
|
||||
DateTimeOffset.Now)
|
||||
<= 0)
|
||||
{
|
||||
var tenantId = config["tenant-id"];
|
||||
var clientId = config["client-id"];
|
||||
var apiServerId = config["apiserver-id"];
|
||||
var refresh = config["refresh-token"];
|
||||
var newToken = RenewAzureToken(tenantId
|
||||
, clientId
|
||||
, apiServerId
|
||||
, refresh);
|
||||
var newToken = RenewAzureToken(tenantId,
|
||||
clientId,
|
||||
apiServerId,
|
||||
refresh);
|
||||
config["access-token"] = newToken;
|
||||
}
|
||||
}
|
||||
@@ -364,6 +363,7 @@ namespace k8s
|
||||
userCredentialsFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case "gcp":
|
||||
{
|
||||
// config
|
||||
@@ -416,9 +416,9 @@ namespace k8s
|
||||
{
|
||||
var execInfo = new Dictionary<string, dynamic>
|
||||
{
|
||||
{"apiVersion", config.ApiVersion },
|
||||
{"kind", "ExecCredentials" },
|
||||
{"spec", new Dictionary<string, bool> { {"interactive", Environment.UserInteractive } } },
|
||||
{ "apiVersion", config.ApiVersion },
|
||||
{ "kind", "ExecCredentials" },
|
||||
{ "spec", new Dictionary<string, bool> { { "interactive", Environment.UserInteractive } } },
|
||||
};
|
||||
|
||||
var process = new Process();
|
||||
@@ -508,6 +508,7 @@ namespace k8s
|
||||
{
|
||||
throw new KubeConfigException($"external exec failed missing clientKeyData field in plugin output");
|
||||
}
|
||||
|
||||
return (null, responseObject.Status["clientCertificateData"], responseObject.Status["clientKeyData"]);
|
||||
}
|
||||
else
|
||||
@@ -733,7 +734,7 @@ namespace k8s
|
||||
private static IEnumerable<T> MergeLists<T>(IEnumerable<T> baseList, IEnumerable<T> mergeList,
|
||||
Func<T, string> getNameFunc)
|
||||
{
|
||||
if (mergeList != null && mergeList.Count() > 0)
|
||||
if (mergeList != null && mergeList.Any())
|
||||
{
|
||||
var mapping = new Dictionary<string, T>();
|
||||
foreach (var item in baseList)
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace k8s
|
||||
{
|
||||
public partial class KubernetesClientConfiguration
|
||||
{
|
||||
private static string ServiceAccountPath =
|
||||
private static string serviceAccountPath =
|
||||
Path.Combine(new string[]
|
||||
{
|
||||
$"{Path.DirectorySeparatorChar}var", "run", "secrets", "kubernetes.io", "serviceaccount",
|
||||
@@ -16,7 +16,7 @@ namespace k8s
|
||||
private const string ServiceAccountTokenKeyFileName = "token";
|
||||
private const string ServiceAccountRootCAKeyFileName = "ca.crt";
|
||||
|
||||
public static Boolean IsInCluster()
|
||||
public static bool IsInCluster()
|
||||
{
|
||||
var host = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST");
|
||||
var port = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_PORT");
|
||||
@@ -25,13 +25,13 @@ namespace k8s
|
||||
return false;
|
||||
}
|
||||
|
||||
var tokenPath = Path.Combine(ServiceAccountPath, ServiceAccountTokenKeyFileName);
|
||||
var tokenPath = Path.Combine(serviceAccountPath, ServiceAccountTokenKeyFileName);
|
||||
if (!File.Exists(tokenPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var certPath = Path.Combine(ServiceAccountPath, ServiceAccountRootCAKeyFileName);
|
||||
var certPath = Path.Combine(serviceAccountPath, ServiceAccountRootCAKeyFileName);
|
||||
return File.Exists(certPath);
|
||||
}
|
||||
|
||||
@@ -43,14 +43,14 @@ namespace k8s
|
||||
"unable to load in-cluster configuration, KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT must be defined");
|
||||
}
|
||||
|
||||
var rootCAFile = Path.Combine(ServiceAccountPath, ServiceAccountRootCAKeyFileName);
|
||||
var rootCAFile = Path.Combine(serviceAccountPath, ServiceAccountRootCAKeyFileName);
|
||||
var host = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST");
|
||||
var port = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_PORT");
|
||||
|
||||
return new KubernetesClientConfiguration
|
||||
{
|
||||
Host = new UriBuilder("https", host, Convert.ToInt32(port)).ToString(),
|
||||
TokenProvider = new TokenFileAuth(Path.Combine(ServiceAccountPath, ServiceAccountTokenKeyFileName)),
|
||||
TokenProvider = new TokenFileAuth(Path.Combine(serviceAccountPath, ServiceAccountTokenKeyFileName)),
|
||||
SslCaCerts = CertUtils.LoadPemFileCert(rootCAFile),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace k8s.Models
|
||||
/// <summary>
|
||||
/// Describes object type in Kubernetes
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class KubernetesEntityAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -17,7 +17,6 @@ namespace k8s.Models
|
||||
Metadata = metadata;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets aPIVersion defines the versioned schema of this
|
||||
/// representation of an object. Servers should convert recognized
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
///<summary>Adds convenient extensions for Kubernetes objects.</summary>
|
||||
/// <summary>Adds convenient extensions for Kubernetes objects.</summary>
|
||||
public static class ModelExtensions
|
||||
{
|
||||
///<summary>Adds the given finalizer to a Kubernetes object if it doesn't already exist.</summary>
|
||||
///<returns>Returns true if the finalizer was added and false if it already existed.</returns>
|
||||
/// <summary>Adds the given finalizer to a Kubernetes object if it doesn't already exist.</summary>
|
||||
/// <returns>Returns true if the finalizer was added and false if it already existed.</returns>
|
||||
public static bool AddFinalizer(this IMetadata<V1ObjectMeta> obj, string finalizer)
|
||||
{
|
||||
if (string.IsNullOrEmpty(finalizer))
|
||||
@@ -505,20 +504,4 @@ namespace k8s.Models
|
||||
owner.Uid == obj.Uid();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class V1Status
|
||||
{
|
||||
/// <summary>Converts a <see cref="V1Status"/> object into a short description of the status.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
string reason = Reason;
|
||||
if (string.IsNullOrEmpty(reason) && Code.GetValueOrDefault() != 0)
|
||||
{
|
||||
reason = ((HttpStatusCode)Code.Value).ToString();
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(Message) ? string.IsNullOrEmpty(reason) ? Status : reason :
|
||||
string.IsNullOrEmpty(reason) ? Message : $"{reason} - {Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
32
src/KubernetesClient/QuantityConverter.cs
Normal file
32
src/KubernetesClient/QuantityConverter.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
internal class QuantityConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var q = (ResourceQuantity)value;
|
||||
|
||||
if (q != null)
|
||||
{
|
||||
serializer.Serialize(writer, q.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
serializer.Serialize(writer, value);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
return new ResourceQuantity(serializer.Deserialize<string>(reader));
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(string);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,33 +11,6 @@ using YamlDotNet.Serialization;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
internal class QuantityConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
var q = (ResourceQuantity)value;
|
||||
|
||||
if (q != null)
|
||||
{
|
||||
serializer.Serialize(writer, q.ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
serializer.Serialize(writer, value);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
return new ResourceQuantity(serializer.Deserialize<string>(reader));
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(string);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// port https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go to c#
|
||||
/// Quantity is a fixed-point representation of a number.
|
||||
@@ -166,7 +139,7 @@ namespace k8s.Models
|
||||
{
|
||||
if (suffixFormat == SuffixFormat.BinarySI)
|
||||
{
|
||||
if (-1024 < _unitlessValue && _unitlessValue < 1024)
|
||||
if (_unitlessValue > -1024 && _unitlessValue < 1024)
|
||||
{
|
||||
return Suffixer.AppendMaxSuffix(_unitlessValue, SuffixFormat.DecimalSI);
|
||||
}
|
||||
@@ -253,8 +226,6 @@ namespace k8s.Models
|
||||
return new ResourceQuantity(v, 0, SuffixFormat.DecimalExponent);
|
||||
}
|
||||
|
||||
#region suffixer
|
||||
|
||||
private class Suffixer
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<string, (int, int)> BinSuffixes =
|
||||
@@ -262,28 +233,28 @@ namespace k8s.Models
|
||||
{
|
||||
// Don't emit an error when trying to produce
|
||||
// a suffix for 2^0.
|
||||
{"", (2, 0) },
|
||||
{"Ki", (2, 10) },
|
||||
{"Mi", (2, 20) },
|
||||
{"Gi", (2, 30) },
|
||||
{"Ti", (2, 40) },
|
||||
{"Pi", (2, 50) },
|
||||
{"Ei", (2, 60) },
|
||||
{ "", (2, 0) },
|
||||
{ "Ki", (2, 10) },
|
||||
{ "Mi", (2, 20) },
|
||||
{ "Gi", (2, 30) },
|
||||
{ "Ti", (2, 40) },
|
||||
{ "Pi", (2, 50) },
|
||||
{ "Ei", (2, 60) },
|
||||
};
|
||||
|
||||
private static readonly IReadOnlyDictionary<string, (int, int)> DecSuffixes =
|
||||
new Dictionary<string, (int, int)>
|
||||
{
|
||||
{"n", (10, -9) },
|
||||
{"u", (10, -6) },
|
||||
{"m", (10, -3) },
|
||||
{"", (10, 0) },
|
||||
{"k", (10, 3) },
|
||||
{"M", (10, 6) },
|
||||
{"G", (10, 9) },
|
||||
{"T", (10, 12) },
|
||||
{"P", (10, 15) },
|
||||
{"E", (10, 18) },
|
||||
{ "n", (10, -9) },
|
||||
{ "u", (10, -6) },
|
||||
{ "m", (10, -3) },
|
||||
{ "", (10, 0) },
|
||||
{ "k", (10, 3) },
|
||||
{ "M", (10, 6) },
|
||||
{ "G", (10, 9) },
|
||||
{ "T", (10, 12) },
|
||||
{ "P", (10, 15) },
|
||||
{ "E", (10, 18) },
|
||||
};
|
||||
|
||||
public Suffixer(string suffix)
|
||||
@@ -325,7 +296,6 @@ namespace k8s.Models
|
||||
public int Base { get; }
|
||||
public int Exponent { get; }
|
||||
|
||||
|
||||
public static string AppendMaxSuffix(Fraction value, SuffixFormat format)
|
||||
{
|
||||
if (value.IsZero)
|
||||
@@ -352,7 +322,6 @@ namespace k8s.Models
|
||||
lastv = v;
|
||||
}
|
||||
|
||||
|
||||
if (minE == 0)
|
||||
{
|
||||
return $"{(decimal)lastv}";
|
||||
@@ -402,7 +371,5 @@ namespace k8s.Models
|
||||
return lastv;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace k8s
|
||||
private readonly StreamType streamType;
|
||||
private readonly bool ownsSocket;
|
||||
private Task runLoop;
|
||||
private bool disposedValue;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="StreamDemuxer"/> class.
|
||||
@@ -58,31 +59,9 @@ namespace k8s
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
this.runLoop = Task.Run(async () => await this.RunLoop(this.cts.Token));
|
||||
this.runLoop = Task.Run(async () => await RunLoop(cts.Token).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.runLoop != null)
|
||||
{
|
||||
this.cts.Cancel();
|
||||
this.runLoop.Wait();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Dispose methods can never throw.
|
||||
Debug.Write(ex);
|
||||
}
|
||||
|
||||
if (this.ownsSocket)
|
||||
{
|
||||
this.webSocket.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="Stream"/> which allows you to read to and/or write from a remote channel.
|
||||
@@ -276,5 +255,49 @@ namespace k8s
|
||||
this.ConnectionClosed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.runLoop != null)
|
||||
{
|
||||
this.cts.Cancel();
|
||||
this.runLoop.Wait();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Dispose methods can never throw.
|
||||
Debug.Write(ex);
|
||||
}
|
||||
|
||||
if (this.ownsSocket)
|
||||
{
|
||||
this.webSocket.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~StreamDemuxer()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,26 +4,6 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
internal class V1PathJsonConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
serializer.Serialize(writer, (value as V1Patch)?.Content);
|
||||
}
|
||||
|
||||
// no read patch object supported at the moment
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(V1Patch);
|
||||
}
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(V1PathJsonConverter))]
|
||||
public partial class V1Patch
|
||||
{
|
||||
|
||||
25
src/KubernetesClient/V1PathJsonConverter.cs
Normal file
25
src/KubernetesClient/V1PathJsonConverter.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
internal class V1PathJsonConverter : JsonConverter
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
serializer.Serialize(writer, (value as V1Patch)?.Content);
|
||||
}
|
||||
|
||||
// no read patch object supported at the moment
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return objectType == typeof(V1Patch);
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/KubernetesClient/V1Status.cs
Normal file
20
src/KubernetesClient/V1Status.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Net;
|
||||
|
||||
namespace k8s.Models
|
||||
{
|
||||
public partial class V1Status
|
||||
{
|
||||
/// <summary>Converts a <see cref="V1Status"/> object into a short description of the status.</summary>
|
||||
public override string ToString()
|
||||
{
|
||||
string reason = Reason;
|
||||
if (string.IsNullOrEmpty(reason) && Code.GetValueOrDefault() != 0)
|
||||
{
|
||||
reason = ((HttpStatusCode)Code.Value).ToString();
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(Message) ? string.IsNullOrEmpty(reason) ? Status : reason :
|
||||
string.IsNullOrEmpty(reason) ? Message : $"{reason} - {Message}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace k8s.Versioning
|
||||
public class KubernetesVersionComparer : IComparer<string>
|
||||
{
|
||||
public static KubernetesVersionComparer Instance { get; private set; }
|
||||
static readonly Regex _kubernetesVersionRegex;
|
||||
private static readonly Regex _kubernetesVersionRegex;
|
||||
|
||||
static KubernetesVersionComparer()
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace k8s.Versioning
|
||||
{
|
||||
Alpha = 1,
|
||||
Beta = 2,
|
||||
Final = 3
|
||||
Final = 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,7 @@ using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using k8s.Exceptions;
|
||||
using k8s.Models;
|
||||
using Microsoft.Rest;
|
||||
using Microsoft.Rest.Serialization;
|
||||
|
||||
namespace k8s
|
||||
@@ -44,6 +42,7 @@ namespace k8s
|
||||
private readonly Func<Task<TextReader>> _streamReaderCreator;
|
||||
|
||||
private TextReader _streamReader;
|
||||
private bool disposedValue;
|
||||
private readonly Task _watcherLoop;
|
||||
|
||||
/// <summary>
|
||||
@@ -93,14 +92,7 @@ namespace k8s
|
||||
OnClosed += onClosed;
|
||||
|
||||
_cts = new CancellationTokenSource();
|
||||
_watcherLoop = Task.Run(async () => await this.WatcherLoop(_cts.Token));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
_cts.Cancel();
|
||||
_streamReader?.Dispose();
|
||||
_watcherLoop = Task.Run(async () => await WatcherLoop(_cts.Token).ConfigureAwait(false));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -176,58 +168,33 @@ namespace k8s
|
||||
OnClosed?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class WatcherExt
|
||||
{
|
||||
/// <summary>
|
||||
/// create a watch object from a call to api server with watch=true
|
||||
/// </summary>
|
||||
/// <typeparam name="T">type of the event object</typeparam>
|
||||
/// <typeparam name="L">type of the HttpOperationResponse object</typeparam>
|
||||
/// <param name="response">the api response</param>
|
||||
/// <param name="onEvent">a callback when any event raised from api server</param>
|
||||
/// <param name="onError">a callbak when any exception was caught during watching</param>
|
||||
/// <param name="onClosed">
|
||||
/// The action to invoke when the server closes the connection.
|
||||
/// </param>
|
||||
/// <returns>a watch object</returns>
|
||||
public static Watcher<T> Watch<T, L>(this Task<HttpOperationResponse<L>> responseTask,
|
||||
Action<WatchEventType, T> onEvent,
|
||||
Action<Exception> onError = null,
|
||||
Action onClosed = null)
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
return new Watcher<T>(async () =>
|
||||
if (!disposedValue)
|
||||
{
|
||||
var response = await responseTask.ConfigureAwait(false);
|
||||
|
||||
if (!(response.Response.Content is WatcherDelegatingHandler.LineSeparatedHttpContent content))
|
||||
if (disposing)
|
||||
{
|
||||
throw new KubernetesClientException("not a watchable request or failed response");
|
||||
_cts.Cancel();
|
||||
_streamReader?.Dispose();
|
||||
}
|
||||
|
||||
return content.StreamReader;
|
||||
}, onEvent, onError, onClosed);
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// create a watch object from a call to api server with watch=true
|
||||
/// </summary>
|
||||
/// <typeparam name="T">type of the event object</typeparam>
|
||||
/// <typeparam name="L">type of the HttpOperationResponse object</typeparam>
|
||||
/// <param name="response">the api response</param>
|
||||
/// <param name="onEvent">a callback when any event raised from api server</param>
|
||||
/// <param name="onError">a callbak when any exception was caught during watching</param>
|
||||
/// <param name="onClosed">
|
||||
/// The action to invoke when the server closes the connection.
|
||||
/// </param>
|
||||
/// <returns>a watch object</returns>
|
||||
public static Watcher<T> Watch<T, L>(this HttpOperationResponse<L> response,
|
||||
Action<WatchEventType, T> onEvent,
|
||||
Action<Exception> onError = null,
|
||||
Action onClosed = null)
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~Watcher()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
return Watch(Task.FromResult(response), onEvent, onError, onClosed);
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace k8s
|
||||
{
|
||||
var originResponse = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (originResponse.IsSuccessStatusCode && request.Method == HttpMethod.Get) // all watches are GETs, so we can ignore others
|
||||
// all watches are GETs, so we can ignore others
|
||||
if (originResponse.IsSuccessStatusCode && request.Method == HttpMethod.Get)
|
||||
{
|
||||
string query = request.RequestUri.Query;
|
||||
int index = query.IndexOf("watch=true");
|
||||
|
||||
60
src/KubernetesClient/WatcherExt.cs
Normal file
60
src/KubernetesClient/WatcherExt.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using k8s.Exceptions;
|
||||
using Microsoft.Rest;
|
||||
|
||||
namespace k8s
|
||||
{
|
||||
public static class WatcherExt
|
||||
{
|
||||
/// <summary>
|
||||
/// create a watch object from a call to api server with watch=true
|
||||
/// </summary>
|
||||
/// <typeparam name="T">type of the event object</typeparam>
|
||||
/// <typeparam name="L">type of the HttpOperationResponse object</typeparam>
|
||||
/// <param name="response">the api response</param>
|
||||
/// <param name="onEvent">a callback when any event raised from api server</param>
|
||||
/// <param name="onError">a callbak when any exception was caught during watching</param>
|
||||
/// <param name="onClosed">
|
||||
/// The action to invoke when the server closes the connection.
|
||||
/// </param>
|
||||
/// <returns>a watch object</returns>
|
||||
public static Watcher<T> Watch<T, L>(this Task<HttpOperationResponse<L>> responseTask,
|
||||
Action<WatchEventType, T> onEvent,
|
||||
Action<Exception> onError = null,
|
||||
Action onClosed = null)
|
||||
{
|
||||
return new Watcher<T>(async () =>
|
||||
{
|
||||
var response = await responseTask.ConfigureAwait(false);
|
||||
|
||||
if (!(response.Response.Content is WatcherDelegatingHandler.LineSeparatedHttpContent content))
|
||||
{
|
||||
throw new KubernetesClientException("not a watchable request or failed response");
|
||||
}
|
||||
|
||||
return content.StreamReader;
|
||||
}, onEvent, onError, onClosed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// create a watch object from a call to api server with watch=true
|
||||
/// </summary>
|
||||
/// <typeparam name="T">type of the event object</typeparam>
|
||||
/// <typeparam name="L">type of the HttpOperationResponse object</typeparam>
|
||||
/// <param name="response">the api response</param>
|
||||
/// <param name="onEvent">a callback when any event raised from api server</param>
|
||||
/// <param name="onError">a callbak when any exception was caught during watching</param>
|
||||
/// <param name="onClosed">
|
||||
/// The action to invoke when the server closes the connection.
|
||||
/// </param>
|
||||
/// <returns>a watch object</returns>
|
||||
public static Watcher<T> Watch<T, L>(this HttpOperationResponse<L> response,
|
||||
Action<WatchEventType, T> onEvent,
|
||||
Action<Exception> onError = null,
|
||||
Action onClosed = null)
|
||||
{
|
||||
return Watch(Task.FromResult(response), onEvent, onError, onClosed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace k8s
|
||||
{
|
||||
public bool Accepts(Type type)
|
||||
{
|
||||
return type == typeof(System.Byte[]);
|
||||
return type == typeof(byte[]);
|
||||
}
|
||||
|
||||
public object ReadYaml(IParser parser, Type type)
|
||||
@@ -49,7 +49,7 @@ namespace k8s
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object value, Type type)
|
||||
{
|
||||
var obj = (System.Byte[])value;
|
||||
var obj = (byte[])value;
|
||||
emitter.Emit(new YamlDotNet.Core.Events.Scalar(Encoding.UTF8.GetString(obj)));
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ namespace k8s
|
||||
/// <param name="typeMap">
|
||||
/// A map from <apiVersion>/<kind> to Type. For example "v1/Pod" -> typeof(V1Pod)
|
||||
/// </param>
|
||||
public static async Task<List<object>> LoadAllFromStreamAsync(Stream stream, Dictionary<String, Type> typeMap)
|
||||
public static async Task<List<object>> LoadAllFromStreamAsync(Stream stream, Dictionary<string, Type> typeMap)
|
||||
{
|
||||
var reader = new StreamReader(stream);
|
||||
var content = await reader.ReadToEndAsync().ConfigureAwait(false);
|
||||
@@ -79,7 +79,7 @@ namespace k8s
|
||||
/// <param name="typeMap">
|
||||
/// A map from <apiVersion>/<kind> to Type. For example "v1/Pod" -> typeof(V1Pod)
|
||||
/// </param>
|
||||
public static Task<List<object>> LoadAllFromFileAsync(String fileName, Dictionary<String, Type> typeMap)
|
||||
public static Task<List<object>> LoadAllFromFileAsync(string fileName, Dictionary<string, Type> typeMap)
|
||||
{
|
||||
var reader = File.OpenRead(fileName);
|
||||
return LoadAllFromStreamAsync(reader, typeMap);
|
||||
@@ -94,7 +94,7 @@ namespace k8s
|
||||
/// <param name="typeMap">
|
||||
/// A map from <apiVersion>/<kind> to Type. For example "v1/Pod" -> typeof(V1Pod)
|
||||
/// </param>
|
||||
public static List<object> LoadAllFromString(String content, Dictionary<String, Type> typeMap)
|
||||
public static List<object> LoadAllFromString(string content, Dictionary<string, Type> typeMap)
|
||||
{
|
||||
var deserializer =
|
||||
new DeserializerBuilder()
|
||||
@@ -221,7 +221,7 @@ namespace k8s
|
||||
// This might have been renamed by AutoRest. See if there is a
|
||||
// JsonPropertyAttribute.PropertyName and use that instead if there is.
|
||||
var jpa = pd.GetCustomAttribute<JsonPropertyAttribute>();
|
||||
if (jpa == null || String.IsNullOrEmpty(jpa.PropertyName))
|
||||
if (jpa == null || string.IsNullOrEmpty(jpa.PropertyName))
|
||||
{
|
||||
return pd;
|
||||
}
|
||||
|
||||
320
src/KubernetesClient/generated/ModelOperators.cs
generated
320
src/KubernetesClient/generated/ModelOperators.cs
generated
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,6 @@ using k8s.Models;
|
||||
|
||||
namespace k8s.Versioning
|
||||
{
|
||||
|
||||
|
||||
public static partial class VersionConverter
|
||||
{
|
||||
private static void AutoConfigurations(IMapperConfigurationExpression cfg)
|
||||
@@ -155,6 +153,4 @@ namespace k8s.Versioning
|
||||
cfg.CreateMap<V1beta1VolumeNodeResources, V1VolumeNodeResources>().ReverseMap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -321,6 +321,7 @@ namespace k8s.Tests
|
||||
Assert.True(listTask.Response.IsSuccessStatusCode);
|
||||
Assert.Equal(1, listTask.Body.Items.Count);
|
||||
}
|
||||
|
||||
{
|
||||
var clientCertificateText = File.ReadAllText("assets/client.crt").Replace("\n", "\\n");
|
||||
var clientCertificateKeyText = File.ReadAllText("assets/client.key").Replace("\n", "\\n");
|
||||
@@ -357,7 +358,6 @@ namespace k8s.Tests
|
||||
}))
|
||||
{
|
||||
{
|
||||
|
||||
var responseJson = $"{{\"apiVersion\":\"testingversion\",\"status\":{{\"token\":\"{token}\"}}}}";
|
||||
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name);
|
||||
var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name);
|
||||
@@ -366,6 +366,7 @@ namespace k8s.Tests
|
||||
Assert.True(listTask.Response.IsSuccessStatusCode);
|
||||
Assert.Equal(1, listTask.Body.Items.Count);
|
||||
}
|
||||
|
||||
{
|
||||
var responseJson = "{\"apiVersion\":\"testingversion\",\"status\":{\"token\":\"wrong_token\"}}";
|
||||
var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), responseJson, name);
|
||||
@@ -421,7 +422,6 @@ namespace k8s.Tests
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration
|
||||
{
|
||||
@@ -472,16 +472,15 @@ namespace k8s.Tests
|
||||
|
||||
var contexts = new List<Context>
|
||||
{
|
||||
new Context {Name = name, ContextDetails = new ContextDetails {Cluster = name, User = username } },
|
||||
new Context { Name = name, ContextDetails = new ContextDetails { Cluster = name, User = username } },
|
||||
};
|
||||
|
||||
{
|
||||
var clusters = new List<Cluster>
|
||||
{
|
||||
new Cluster
|
||||
{
|
||||
Name = name,
|
||||
ClusterEndpoint = new ClusterEndpoint {SkipTlsVerify = true, Server = serverUri }
|
||||
ClusterEndpoint = new ClusterEndpoint { SkipTlsVerify = true, Server = serverUri },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -518,9 +517,9 @@ namespace k8s.Tests
|
||||
{
|
||||
ApiVersion = "testingversion",
|
||||
Command = command,
|
||||
Arguments = arguments.ToList()
|
||||
}
|
||||
}
|
||||
Arguments = arguments.ToList(),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
var kubernetesConfig = new K8SConfiguration { Clusters = clusters, Users = users, Contexts = contexts };
|
||||
|
||||
@@ -256,7 +256,7 @@ namespace k8s.Tests
|
||||
|
||||
// Kick off a read operation
|
||||
var readTask = Task.Run(() => read = buffer.Read(readData, 0, readData.Length));
|
||||
await Task.Delay(250);
|
||||
await Task.Delay(250).ConfigureAwait(false);
|
||||
Assert.False(readTask.IsCompleted, "Read task completed before data was available.");
|
||||
|
||||
// Write data to the buffer
|
||||
@@ -264,7 +264,7 @@ namespace k8s.Tests
|
||||
|
||||
await TaskAssert.Completed(readTask,
|
||||
timeout: TimeSpan.FromMilliseconds(1000),
|
||||
message: "Timed out waiting for read task to complete.");
|
||||
message: "Timed out waiting for read task to complete.").ConfigureAwait(false);
|
||||
|
||||
Assert.Equal(3, read);
|
||||
Assert.Equal(0xF0, readData[0]);
|
||||
@@ -411,10 +411,10 @@ namespace k8s.Tests
|
||||
byte[] output = new byte[buffer.Size + 1];
|
||||
|
||||
var readTask = Task.Run(() => buffer.Read(output, 0, output.Length));
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
|
||||
|
||||
buffer.Write(data, 0, data.Length);
|
||||
await readTask;
|
||||
await readTask.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
#if NETCOREAPP2_0
|
||||
@@ -437,12 +437,12 @@ namespace k8s.Tests
|
||||
var consumerTask
|
||||
= Task.Run(() => this.Consume(buffer, SHA256.Create()));
|
||||
|
||||
await Task.WhenAll(generatorTask, consumerTask);
|
||||
await Task.WhenAll(generatorTask, consumerTask).ConfigureAwait(false);
|
||||
|
||||
var generatorHash
|
||||
= await generatorTask;
|
||||
= await generatorTask.ConfigureAwait(false);
|
||||
var consumerHash
|
||||
= await consumerTask;
|
||||
= await consumerTask.ConfigureAwait(false);
|
||||
|
||||
Assert.Equal(generatorHash, consumerHash);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace k8s.Tests
|
||||
Command = "command",
|
||||
Arguments = new List<string> { "arg1", "arg2" },
|
||||
EnvironmentVariables = new List<Dictionary<string, string>>
|
||||
{ new Dictionary<string, string> { { "name", "testkey" }, { "value", "testvalue" } } }
|
||||
{ new Dictionary<string, string> { { "name", "testkey" }, { "value", "testvalue" } } },
|
||||
});
|
||||
|
||||
var actualExecInfo = JsonConvert.DeserializeObject<Dictionary<string, dynamic>>(actual.StartInfo.EnvironmentVariables["KUBERNETES_EXEC_INFO"]);
|
||||
|
||||
@@ -19,8 +19,9 @@ namespace k8s.Tests
|
||||
{
|
||||
System.Diagnostics.Process.Start("chmod", $"+x {cmd}").WaitForExit();
|
||||
}
|
||||
|
||||
var sut = new GcpTokenProvider(cmd);
|
||||
var result = await sut.GetAuthenticationHeaderAsync(CancellationToken.None);
|
||||
var result = await sut.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
result.Scheme.Should().Be("Bearer");
|
||||
result.Parameter.Should().Be("ACCESS-TOKEN");
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<SignAssembly>true</SignAssembly>
|
||||
<AssemblyOriginatorKeyFile>..\..\src\KubernetesClient\kubernetes-client.snk</AssemblyOriginatorKeyFile>
|
||||
<RootNamespace>k8s.Tests</RootNamespace>
|
||||
<TargetFrameworks>netcoreapp2.1;netcoreapp2.0</TargetFrameworks>
|
||||
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -20,12 +20,12 @@
|
||||
<PackageReference Include="Nito.AsyncEx" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
|
||||
<!-- <ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">
|
||||
<Compile Remove="Kubernetes.Exec.Tests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
|
||||
<Compile Remove="Kubernetes.WebSockets.Tests.cs" />
|
||||
</ItemGroup>
|
||||
</ItemGroup> -->
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
@@ -434,7 +434,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LoadKubeConfigFromEnvironmentVariable_MultipleConfigs()
|
||||
public void LoadKubeConfigFromEnvironmentVariableMultipleConfigs()
|
||||
{
|
||||
// This test makes sure that a list of environment variables works (no exceptions),
|
||||
// doesn't check validity of configuration, which is done in other tests.
|
||||
@@ -564,7 +564,7 @@ namespace k8s.Tests
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertContextEqual(Context expected, Context actual)
|
||||
private static void AssertContextEqual(Context expected, Context actual)
|
||||
{
|
||||
Assert.Equal(expected.Name, actual.Name);
|
||||
Assert.Equal(expected.ContextDetails.Cluster, actual.ContextDetails.Cluster);
|
||||
@@ -572,7 +572,7 @@ namespace k8s.Tests
|
||||
Assert.Equal(expected.ContextDetails.Namespace, actual.ContextDetails.Namespace);
|
||||
}
|
||||
|
||||
private void AssertClusterEqual(Cluster expected, Cluster actual)
|
||||
private static void AssertClusterEqual(Cluster expected, Cluster actual)
|
||||
{
|
||||
Assert.Equal(expected.Name, actual.Name);
|
||||
Assert.Equal(expected.ClusterEndpoint.CertificateAuthority, actual.ClusterEndpoint.CertificateAuthority);
|
||||
@@ -582,7 +582,7 @@ namespace k8s.Tests
|
||||
Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify);
|
||||
}
|
||||
|
||||
private void AssertUserEqual(User expected, User actual)
|
||||
private static void AssertUserEqual(User expected, User actual)
|
||||
{
|
||||
Assert.Equal(expected.Name, actual.Name);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#if !NETCOREAPP2_1
|
||||
/*
|
||||
* These tests are only for the netstandard version of the client (there are separate tests for netcoreapp that connect to a local test-hosted server).
|
||||
*/
|
||||
@@ -153,3 +154,4 @@ namespace k8s.Tests
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -8,7 +8,7 @@ namespace k8s.Tests.Logging
|
||||
/// <summary>
|
||||
/// An implementation of <see cref="ILogger"/> that writes to the output of the current Xunit test.
|
||||
/// </summary>
|
||||
sealed class TestOutputLogger
|
||||
internal sealed class TestOutputLogger
|
||||
: ILogger
|
||||
{
|
||||
/// <summary>
|
||||
@@ -30,7 +30,7 @@ namespace k8s.Tests.Logging
|
||||
throw new ArgumentNullException(nameof(testOutput));
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(loggerCategory))
|
||||
if (string.IsNullOrWhiteSpace(loggerCategory))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Argument cannot be null, empty, or entirely composed of whitespace: 'loggerCategory'.",
|
||||
@@ -83,7 +83,7 @@ namespace k8s.Tests.Logging
|
||||
throw new ArgumentNullException(nameof(formatter));
|
||||
}
|
||||
|
||||
TestOutput.WriteLine(String.Format("[{0}] {1}: {2}",
|
||||
TestOutput.WriteLine(string.Format("[{0}] {1}: {2}",
|
||||
level,
|
||||
LoggerCategory,
|
||||
formatter(state, exception)));
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace k8s.Tests.Logging
|
||||
/// <summary>
|
||||
/// Logger provider for logging to Xunit test output.
|
||||
/// </summary>
|
||||
sealed class TestOutputLoggerProvider
|
||||
internal sealed class TestOutputLoggerProvider
|
||||
: ILoggerProvider
|
||||
{
|
||||
/// <summary>
|
||||
@@ -40,7 +40,7 @@ namespace k8s.Tests.Logging
|
||||
/// <summary>
|
||||
/// The output for the current test.
|
||||
/// </summary>
|
||||
ITestOutputHelper TestOutput { get; }
|
||||
private ITestOutputHelper TestOutput { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The logger's minimum log level.
|
||||
|
||||
@@ -32,9 +32,9 @@ namespace k8s.Tests.Mock
|
||||
_webHost = WebHost.CreateDefaultBuilder()
|
||||
.Configure(app => app.Run(async httpContext =>
|
||||
{
|
||||
if (await shouldNext(httpContext))
|
||||
if (await shouldNext(httpContext).ConfigureAwait(false))
|
||||
{
|
||||
await httpContext.Response.WriteAsync(resp);
|
||||
await httpContext.Response.WriteAsync(resp).ConfigureAwait(false);
|
||||
}
|
||||
}))
|
||||
.UseKestrel(options => { options.Listen(IPAddress.Loopback, 0, listenConfigure); })
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace k8s.Tests.Mock
|
||||
private string subProtocol;
|
||||
private ConcurrentQueue<MessageData> receiveBuffers = new ConcurrentQueue<MessageData>();
|
||||
private AsyncAutoResetEvent receiveEvent = new AsyncAutoResetEvent(false);
|
||||
private bool disposedValue;
|
||||
|
||||
public MockWebSocket(string subProtocol = null)
|
||||
{
|
||||
@@ -26,7 +27,7 @@ namespace k8s.Tests.Mock
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public EventHandler<MessageDataEventArgs> MessageSent;
|
||||
public EventHandler<MessageDataEventArgs> MessageSent { get; set; }
|
||||
|
||||
public Task InvokeReceiveAsync(ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage)
|
||||
{
|
||||
@@ -40,8 +41,6 @@ namespace k8s.Tests.Mock
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#region WebSocket overrides
|
||||
|
||||
public override WebSocketCloseStatus? CloseStatus => this.closeStatus;
|
||||
|
||||
public override string CloseStatusDescription => this.closeStatusDescription;
|
||||
@@ -76,12 +75,6 @@ namespace k8s.Tests.Mock
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
this.receiveBuffers.Clear();
|
||||
this.receiveEvent.Set();
|
||||
}
|
||||
|
||||
public override async Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -127,14 +120,12 @@ namespace k8s.Tests.Mock
|
||||
{
|
||||
Buffer = buffer,
|
||||
MessageType = messageType,
|
||||
EndOfMessage = endOfMessage
|
||||
EndOfMessage = endOfMessage,
|
||||
},
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public class MessageData
|
||||
{
|
||||
public ArraySegment<byte> Buffer { get; set; }
|
||||
@@ -146,5 +137,33 @@ namespace k8s.Tests.Mock
|
||||
{
|
||||
public MessageData Data { get; set; }
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
this.receiveBuffers.Clear();
|
||||
this.receiveEvent.Set();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~MockWebSocket()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace k8s.Tests.Mock.Server.Controllers
|
||||
/// <summary>
|
||||
/// The adapter used to capture sockets accepted by the test server and provide them to the calling test.
|
||||
/// </summary>
|
||||
WebSocketTestAdapter WebSocketTestAdapter { get; }
|
||||
private WebSocketTestAdapter WebSocketTestAdapter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Mock Kubernetes API: exec-in-pod.
|
||||
@@ -52,11 +52,11 @@ namespace k8s.Tests.Mock.Server.Controllers
|
||||
}
|
||||
|
||||
WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(
|
||||
subProtocol: WebSocketProtocol.ChannelWebSocketProtocol);
|
||||
subProtocol: WebSocketProtocol.ChannelWebSocketProtocol).ConfigureAwait(false);
|
||||
|
||||
WebSocketTestAdapter.AcceptedPodExecV1Connection.AcceptServerSocket(webSocket);
|
||||
|
||||
await WebSocketTestAdapter.TestCompleted;
|
||||
await WebSocketTestAdapter.TestCompleted.ConfigureAwait(false);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace k8s.Tests.Mock.Server.Controllers
|
||||
/// <summary>
|
||||
/// The adapter used to capture sockets accepted by the test server and provide them to the calling test.
|
||||
/// </summary>
|
||||
WebSocketTestAdapter WebSocketTestAdapter { get; }
|
||||
private WebSocketTestAdapter WebSocketTestAdapter { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Mock Kubernetes API: port-forward for pod.
|
||||
@@ -56,11 +56,11 @@ namespace k8s.Tests.Mock.Server.Controllers
|
||||
}
|
||||
|
||||
WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(
|
||||
subProtocol: WebSocketProtocol.ChannelWebSocketProtocol);
|
||||
subProtocol: WebSocketProtocol.ChannelWebSocketProtocol).ConfigureAwait(false);
|
||||
|
||||
WebSocketTestAdapter.AcceptedPodPortForwardV1Connection.AcceptServerSocket(webSocket);
|
||||
|
||||
await WebSocketTestAdapter.TestCompleted;
|
||||
await WebSocketTestAdapter.TestCompleted.ConfigureAwait(false);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace k8s.Tests.Mock.Server
|
||||
/// <param name="services">
|
||||
/// The service collection to configure.
|
||||
/// </param>
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
public static void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
if (services == null)
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace k8s.Tests.Mock.Server
|
||||
/// <param name="app">
|
||||
/// The application pipeline builder.
|
||||
/// </param>
|
||||
public void Configure(IApplicationBuilder app)
|
||||
public static void Configure(IApplicationBuilder app)
|
||||
{
|
||||
app.UseWebSockets(new WebSocketOptions
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace k8s.Tests.Mock.Server
|
||||
/// <summary>
|
||||
/// Completion source for the <see cref="TestCompleted"/> task.
|
||||
/// </summary>
|
||||
readonly TaskCompletionSource<object> _testCompletion = new TaskCompletionSource<object>();
|
||||
private readonly TaskCompletionSource<object> _testCompletion = new TaskCompletionSource<object>();
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Task"/> that completes when the test is complete (providing <see cref="CompleteTest"/> is called).
|
||||
@@ -51,7 +51,7 @@ namespace k8s.Tests.Mock.Server
|
||||
/// <summary>
|
||||
/// Completion source for the <see cref="ServerSocketAccepted"/> task.
|
||||
/// </summary>
|
||||
readonly TaskCompletionSource<WebSocket> _completion = new TaskCompletionSource<WebSocket>();
|
||||
private readonly TaskCompletionSource<WebSocket> _completion = new TaskCompletionSource<WebSocket>();
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="Task"/> that completes when the server accepts a WebSocket connection (i.e. when <see cref="AcceptServerSocket"/> or <see cref="RejectServerSocket"/> is called).
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace k8s.Tests
|
||||
Name = "name",
|
||||
NamespaceProperty = "ns",
|
||||
ResourceVersion = "42",
|
||||
Uid = "id"
|
||||
Uid = "id",
|
||||
};
|
||||
Assert.Equal(ts, pod.CreationTimestamp().Value);
|
||||
Assert.Equal(ts2, pod.DeletionTimestamp().Value);
|
||||
|
||||
@@ -7,6 +7,6 @@ namespace k8s.Tests
|
||||
{
|
||||
Windows = 1,
|
||||
Linux = 2,
|
||||
OSX = 4
|
||||
OSX = 4,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace k8s.Tests
|
||||
/// Verify that the client can request execution of a command in a pod's default container, with only the STDOUT stream enabled.
|
||||
/// </summary>
|
||||
[Fact(DisplayName = "Can exec in pod's default container, STDOUT only")]
|
||||
public async Task Exec_DefaultContainer_StdOut()
|
||||
public async Task ExecDefaultContainerStdOut()
|
||||
{
|
||||
if (!Debugger.IsAttached)
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace k8s.Tests
|
||||
TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
await Host.StartAsync(TestCancellation);
|
||||
await Host.StartAsync(TestCancellation).ConfigureAwait(false);
|
||||
|
||||
using (Kubernetes client = CreateTestClient())
|
||||
{
|
||||
@@ -66,7 +66,7 @@ namespace k8s.Tests
|
||||
stdin: false,
|
||||
stdout: true,
|
||||
webSocketSubProtol: WebSocketProtocol.ChannelWebSocketProtocol,
|
||||
cancellationToken: TestCancellation);
|
||||
cancellationToken: TestCancellation).ConfigureAwait(false);
|
||||
Assert.Equal(WebSocketProtocol.ChannelWebSocketProtocol,
|
||||
clientSocket
|
||||
.SubProtocol); // For WebSockets, the Kubernetes API defaults to the binary channel (v1) protocol.
|
||||
@@ -81,10 +81,10 @@ namespace k8s.Tests
|
||||
const int STDOUT = 1;
|
||||
const string expectedOutput = "This is text send to STDOUT.";
|
||||
|
||||
int bytesSent = await SendMultiplexed(serverSocket, STDOUT, expectedOutput);
|
||||
int bytesSent = await SendMultiplexed(serverSocket, STDOUT, expectedOutput).ConfigureAwait(false);
|
||||
testOutput.WriteLine($"Sent {bytesSent} bytes to server socket; receiving from client socket...");
|
||||
|
||||
(string receivedText, byte streamIndex, int bytesReceived) = await ReceiveTextMultiplexed(clientSocket);
|
||||
(string receivedText, byte streamIndex, int bytesReceived) = await ReceiveTextMultiplexed(clientSocket).ConfigureAwait(false);
|
||||
testOutput.WriteLine(
|
||||
$"Received {bytesReceived} bytes from client socket ('{receivedText}', stream {streamIndex}).");
|
||||
|
||||
@@ -93,15 +93,14 @@ namespace k8s.Tests
|
||||
|
||||
await Disconnect(clientSocket, serverSocket,
|
||||
closeStatus: WebSocketCloseStatus.NormalClosure,
|
||||
closeStatusDescription: "Normal Closure");
|
||||
closeStatusDescription: "Normal Closure").ConfigureAwait(false);
|
||||
|
||||
WebSocketTestAdapter.CompleteTest();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void GetExitCodeOrThrow_Success()
|
||||
public void GetExitCodeOrThrowSuccess()
|
||||
{
|
||||
var status = new V1Status() { Metadata = null, Status = "Success", };
|
||||
|
||||
@@ -109,7 +108,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetExitCodeOrThrow_NonZeroExitCode()
|
||||
public void GetExitCodeOrThrowNonZeroExitCode()
|
||||
{
|
||||
var status = new V1Status()
|
||||
{
|
||||
@@ -121,8 +120,8 @@ namespace k8s.Tests
|
||||
{
|
||||
Causes = new List<V1StatusCause>()
|
||||
{
|
||||
new V1StatusCause() {Reason = "ExitCode", Message = "1" }
|
||||
}
|
||||
new V1StatusCause() { Reason = "ExitCode", Message = "1" },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -130,7 +129,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetExitCodeOrThrow_InvalidExitCode()
|
||||
public void GetExitCodeOrThrowInvalidExitCode()
|
||||
{
|
||||
var status = new V1Status()
|
||||
{
|
||||
@@ -142,8 +141,8 @@ namespace k8s.Tests
|
||||
{
|
||||
Causes = new List<V1StatusCause>()
|
||||
{
|
||||
new V1StatusCause() {Reason = "ExitCode", Message = "abc" }
|
||||
}
|
||||
new V1StatusCause() { Reason = "ExitCode", Message = "abc" },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -152,7 +151,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetExitCodeOrThrow_NoExitCode()
|
||||
public void GetExitCodeOrThrowNoExitCode()
|
||||
{
|
||||
var status = new V1Status()
|
||||
{
|
||||
@@ -168,7 +167,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetExitCodeOrThrow_OtherError()
|
||||
public void GetExitCodeOrThrowOtherError()
|
||||
{
|
||||
var status = new V1Status() { Metadata = null, Status = "Failure", Reason = "SomethingElse" };
|
||||
|
||||
@@ -177,7 +176,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NamespacedPodExecAsync_ActionNull()
|
||||
public async Task NamespacedPodExecAsyncActionNull()
|
||||
{
|
||||
using (MemoryStream stdIn = new MemoryStream())
|
||||
using (MemoryStream stdOut = new MemoryStream())
|
||||
@@ -209,7 +208,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NamespacedPodExecAsync_HttpException_WithStatus()
|
||||
public async Task NamespacedPodExecAsyncHttpExceptionWithStatus()
|
||||
{
|
||||
var kubernetesMock = new Moq.Mock<Kubernetes>(
|
||||
new object[] { Moq.Mock.Of<ServiceClientCredentials>(), new DelegatingHandler[] { } });
|
||||
@@ -232,7 +231,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NamespacedPodExecAsync_HttpException_NoStatus()
|
||||
public async Task NamespacedPodExecAsyncHttpExceptionNoStatus()
|
||||
{
|
||||
var kubernetesMock = new Moq.Mock<Kubernetes>(
|
||||
new object[] { Moq.Mock.Of<ServiceClientCredentials>(), new DelegatingHandler[] { } });
|
||||
@@ -255,7 +254,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NamespacedPodExecAsync_GenericException()
|
||||
public async Task NamespacedPodExecAsyncGenericException()
|
||||
{
|
||||
var kubernetesMock = new Moq.Mock<Kubernetes>(
|
||||
new object[] { Moq.Mock.Of<ServiceClientCredentials>(), new DelegatingHandler[] { } });
|
||||
@@ -278,7 +277,7 @@ namespace k8s.Tests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task NamespacedPodExecAsync_ExitCode_NonZero()
|
||||
public async Task NamespacedPodExecAsyncExitCodeNonZero()
|
||||
{
|
||||
var processStatus = new V1Status()
|
||||
{
|
||||
@@ -290,8 +289,8 @@ namespace k8s.Tests
|
||||
{
|
||||
Causes = new List<V1StatusCause>()
|
||||
{
|
||||
new V1StatusCause() {Reason = "ExitCode", Message = "1" }
|
||||
}
|
||||
new V1StatusCause() { Reason = "ExitCode", Message = "1" },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace k8s.Tests
|
||||
stream.Write(b, 0, b.Length);
|
||||
|
||||
// Send 100 bytes, expect 1 (channel index) + 100 (payload) = 101 bytes
|
||||
Assert.True(await WaitForAsync(() => sentBuffer.Count == 101),
|
||||
Assert.True(await WaitForAsync(() => sentBuffer.Count == 101).ConfigureAwait(false),
|
||||
$"Demuxer error: expect to send 101 bytes, but actually send {sentBuffer.Count} bytes.");
|
||||
Assert.True(sentBuffer[0] == channelIndex, "The first sent byte is not channel index!");
|
||||
Assert.True(sentBuffer[1] == 0xEF, "Incorrect payload!");
|
||||
@@ -63,7 +63,7 @@ namespace k8s.Tests
|
||||
stream.Write(b, 0, b.Length);
|
||||
|
||||
// Send 300 bytes in 2 messages, expect 1 (channel index) * 2 + 300 (payload) = 302 bytes
|
||||
Assert.True(await WaitForAsync(() => sentBuffer.Count == 302),
|
||||
Assert.True(await WaitForAsync(() => sentBuffer.Count == 302).ConfigureAwait(false),
|
||||
$"Demuxer error: expect to send 302 bytes, but actually send {sentBuffer.Count} bytes.");
|
||||
Assert.True(sentBuffer[0] == channelIndex, "The first sent byte is not channel index!");
|
||||
Assert.True(sentBuffer[1] == 0xEF, "The first part of payload incorrect!");
|
||||
@@ -91,21 +91,21 @@ namespace k8s.Tests
|
||||
{
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(100, channelIndex, 0xAA, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(200, channelIndex, 0xAB, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(300, channelIndex, 0xAC, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
|
||||
await WaitForAsync(() => receivedBuffer.Count == expectedCount);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None);
|
||||
await WaitForAsync(() => receivedBuffer.Count == expectedCount).ConfigureAwait(false);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false);
|
||||
});
|
||||
var buffer = new byte[50];
|
||||
while (true)
|
||||
{
|
||||
var cRead = await stream.ReadAsync(buffer, 0, buffer.Length);
|
||||
var cRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (cRead == 0)
|
||||
{
|
||||
break;
|
||||
@@ -117,7 +117,7 @@ namespace k8s.Tests
|
||||
}
|
||||
}
|
||||
|
||||
await t;
|
||||
await t.ConfigureAwait(false);
|
||||
|
||||
Assert.True(receivedBuffer.Count == expectedCount,
|
||||
$"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes.");
|
||||
@@ -150,21 +150,21 @@ namespace k8s.Tests
|
||||
{
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(100, channelIndex, 0xB1, true)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(200, channelIndex, 0xB2, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(300, channelIndex, 0xB3, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
|
||||
await WaitForAsync(() => receivedBuffer.Count == expectedCount);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None);
|
||||
await WaitForAsync(() => receivedBuffer.Count == expectedCount).ConfigureAwait(false);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false);
|
||||
});
|
||||
var buffer = new byte[50];
|
||||
while (true)
|
||||
{
|
||||
var cRead = await stream.ReadAsync(buffer, 0, buffer.Length);
|
||||
var cRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (cRead == 0)
|
||||
{
|
||||
break;
|
||||
@@ -176,7 +176,7 @@ namespace k8s.Tests
|
||||
}
|
||||
}
|
||||
|
||||
await t;
|
||||
await t.ConfigureAwait(false);
|
||||
|
||||
Assert.True(receivedBuffer.Count == expectedCount,
|
||||
$"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes.");
|
||||
@@ -209,21 +209,21 @@ namespace k8s.Tests
|
||||
{
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(2, channelIndex, 0xC1, true)),
|
||||
WebSocketMessageType.Binary, false);
|
||||
WebSocketMessageType.Binary, false).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(100, channelIndex, 0xC2, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(300, channelIndex, 0xC3, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
|
||||
await WaitForAsync(() => receivedBuffer.Count == expectedCount);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None);
|
||||
await WaitForAsync(() => receivedBuffer.Count == expectedCount).ConfigureAwait(false);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false);
|
||||
});
|
||||
var buffer = new byte[50];
|
||||
while (true)
|
||||
{
|
||||
var cRead = await stream.ReadAsync(buffer, 0, buffer.Length);
|
||||
var cRead = await stream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (cRead == 0)
|
||||
{
|
||||
break;
|
||||
@@ -235,7 +235,7 @@ namespace k8s.Tests
|
||||
}
|
||||
}
|
||||
|
||||
await t;
|
||||
await t.ConfigureAwait(false);
|
||||
|
||||
Assert.True(receivedBuffer.Count == expectedCount,
|
||||
$"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes.");
|
||||
@@ -272,24 +272,24 @@ namespace k8s.Tests
|
||||
// Simulate WebSocket received remote data to multiple streams
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(100, channelIndex1, 0xD1, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(200, channelIndex2, 0xD2, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(300, channelIndex1, 0xD3, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
|
||||
await WaitForAsync(() => receivedBuffer1.Count == expectedCount1);
|
||||
await WaitForAsync(() => receivedBuffer2.Count == expectedCount2);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None);
|
||||
await WaitForAsync(() => receivedBuffer1.Count == expectedCount1).ConfigureAwait(false);
|
||||
await WaitForAsync(() => receivedBuffer2.Count == expectedCount2).ConfigureAwait(false);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false);
|
||||
});
|
||||
var t2 = Task.Run(async () =>
|
||||
{
|
||||
var buffer = new byte[50];
|
||||
while (true)
|
||||
{
|
||||
var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length);
|
||||
var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (cRead == 0)
|
||||
{
|
||||
break;
|
||||
@@ -306,7 +306,7 @@ namespace k8s.Tests
|
||||
var buffer = new byte[50];
|
||||
while (true)
|
||||
{
|
||||
var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length);
|
||||
var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (cRead == 0)
|
||||
{
|
||||
break;
|
||||
@@ -318,7 +318,7 @@ namespace k8s.Tests
|
||||
}
|
||||
}
|
||||
});
|
||||
await Task.WhenAll(t1, t2, t3);
|
||||
await Task.WhenAll(t1, t2, t3).ConfigureAwait(false);
|
||||
|
||||
Assert.True(receivedBuffer1.Count == expectedCount1,
|
||||
$"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes.");
|
||||
@@ -361,24 +361,24 @@ namespace k8s.Tests
|
||||
// Simulate WebSocket received remote data to multiple streams
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(100, channelIndex1, 0xE1, true)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(200, channelIndex2, 0xE2, true)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
await ws.InvokeReceiveAsync(
|
||||
new ArraySegment<byte>(GenerateRandomBuffer(300, channelIndex1, 0xE3, false)),
|
||||
WebSocketMessageType.Binary, true);
|
||||
WebSocketMessageType.Binary, true).ConfigureAwait(false);
|
||||
|
||||
await WaitForAsync(() => receivedBuffer1.Count == expectedCount1);
|
||||
await WaitForAsync(() => receivedBuffer2.Count == expectedCount2);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None);
|
||||
await WaitForAsync(() => receivedBuffer1.Count == expectedCount1).ConfigureAwait(false);
|
||||
await WaitForAsync(() => receivedBuffer2.Count == expectedCount2).ConfigureAwait(false);
|
||||
await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None).ConfigureAwait(false);
|
||||
});
|
||||
var t2 = Task.Run(async () =>
|
||||
{
|
||||
var buffer = new byte[50];
|
||||
while (true)
|
||||
{
|
||||
var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length);
|
||||
var cRead = await stream1.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (cRead == 0)
|
||||
{
|
||||
break;
|
||||
@@ -395,7 +395,7 @@ namespace k8s.Tests
|
||||
var buffer = new byte[50];
|
||||
while (true)
|
||||
{
|
||||
var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length);
|
||||
var cRead = await stream2.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
if (cRead == 0)
|
||||
{
|
||||
break;
|
||||
@@ -407,7 +407,7 @@ namespace k8s.Tests
|
||||
}
|
||||
}
|
||||
});
|
||||
await Task.WhenAll(t1, t2, t3);
|
||||
await Task.WhenAll(t1, t2, t3).ConfigureAwait(false);
|
||||
|
||||
Assert.True(receivedBuffer1.Count == expectedCount1,
|
||||
$"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes.");
|
||||
@@ -465,8 +465,9 @@ namespace k8s.Tests
|
||||
return true;
|
||||
}
|
||||
|
||||
await Task.Delay(10);
|
||||
} while (w.Elapsed.Duration().TotalSeconds < waitForSeconds);
|
||||
await Task.Delay(10).ConfigureAwait(false);
|
||||
}
|
||||
while (w.Elapsed.Duration().TotalSeconds < waitForSeconds);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Xunit;
|
||||
|
||||
namespace k8s.Tests
|
||||
{
|
||||
static class TaskAssert
|
||||
internal static class TaskAssert
|
||||
{
|
||||
public static void NotCompleted(Task task, string message = "Task should not be completed")
|
||||
{
|
||||
@@ -17,25 +17,22 @@ namespace k8s.Tests
|
||||
var timeoutTask = Task.Delay(
|
||||
TimeSpan.FromMilliseconds(1000));
|
||||
|
||||
var completedTask = await Task.WhenAny(task, timeoutTask);
|
||||
var completedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false);
|
||||
Assert.True(ReferenceEquals(task, completedTask), message);
|
||||
|
||||
await completedTask;
|
||||
await completedTask.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public static async Task<T> Completed<T>(Task<T> task, TimeSpan timeout, string message = "Task timed out")
|
||||
{
|
||||
var timeoutTask =
|
||||
Task.Delay(
|
||||
TimeSpan.FromMilliseconds(1000))
|
||||
.ContinueWith(
|
||||
completedTimeoutTask =>
|
||||
default(T)); // Value is never returned, but we need a task of the same result type in order to use Task.WhenAny.
|
||||
var timeoutTask = Task.Delay(TimeSpan.FromMilliseconds(1000)).ContinueWith(completedTimeoutTask => default(T));
|
||||
|
||||
var completedTask = await Task.WhenAny(task, timeoutTask);
|
||||
// Value is never returned, but we need a task of the same result type in order to use Task.WhenAny.
|
||||
|
||||
var completedTask = await Task.WhenAny(task, timeoutTask).ConfigureAwait(false);
|
||||
Assert.True(ReferenceEquals(task, completedTask), message);
|
||||
|
||||
return await completedTask;
|
||||
return await completedTask.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,20 +9,20 @@ namespace k8s.Tests
|
||||
{
|
||||
public class TokenFileAuthTests
|
||||
{
|
||||
public async Task Token()
|
||||
public async Task TestToken()
|
||||
{
|
||||
var auth = new TokenFileAuth("assets/token1");
|
||||
var result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None);
|
||||
var result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
result.Scheme.Should().Be("Bearer");
|
||||
result.Parameter.Should().Be("token1");
|
||||
|
||||
auth._token_file = "assets/token2";
|
||||
result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None);
|
||||
auth.TokenFile = "assets/token2";
|
||||
result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
result.Scheme.Should().Be("Bearer");
|
||||
result.Parameter.Should().Be("token1");
|
||||
|
||||
auth._token_expires_at = DateTime.UtcNow;
|
||||
result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None);
|
||||
auth.TokenExpiresAt = DateTime.UtcNow;
|
||||
result = await auth.GetAuthenticationHeaderAsync(CancellationToken.None).ConfigureAwait(false);
|
||||
result.Scheme.Should().Be("Bearer");
|
||||
result.Parameter.Should().Be("token2");
|
||||
}
|
||||
@@ -27,7 +27,7 @@ namespace k8s.Tests
|
||||
private static readonly string MockDeletedStreamLine = BuildWatchEventStreamLine(WatchEventType.Deleted);
|
||||
private static readonly string MockModifiedStreamLine = BuildWatchEventStreamLine(WatchEventType.Modified);
|
||||
private static readonly string MockErrorStreamLine = BuildWatchEventStreamLine(WatchEventType.Error);
|
||||
private static readonly string MockBadStreamLine = "bad json";
|
||||
private const string MockBadStreamLine = "bad json";
|
||||
private static readonly TimeSpan TestTimeout = TimeSpan.FromSeconds(150);
|
||||
|
||||
private readonly ITestOutputHelper testOutput;
|
||||
@@ -48,9 +48,9 @@ namespace k8s.Tests
|
||||
private static async Task WriteStreamLine(HttpContext httpContext, string reponseLine)
|
||||
{
|
||||
const string crlf = "\r\n";
|
||||
await httpContext.Response.WriteAsync(reponseLine.Replace(crlf, ""));
|
||||
await httpContext.Response.WriteAsync(crlf);
|
||||
await httpContext.Response.Body.FlushAsync();
|
||||
await httpContext.Response.WriteAsync(reponseLine.Replace(crlf, "")).ConfigureAwait(false);
|
||||
await httpContext.Response.WriteAsync(crlf).ConfigureAwait(false);
|
||||
await httpContext.Response.Body.FlushAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -68,7 +68,7 @@ namespace k8s.Tests
|
||||
{
|
||||
}
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(1)); // delay for onerror to be called
|
||||
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); // delay for onerror to be called
|
||||
Assert.True(onErrorCalled);
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace k8s.Tests
|
||||
|
||||
// this line did not throw
|
||||
// listTask.Watch<Corev1Pod>((type, item) => { });
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +92,8 @@ namespace k8s.Tests
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
// block until reponse watcher obj created
|
||||
await created.WaitAsync();
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await created.WaitAsync().ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
@@ -105,7 +105,7 @@ namespace k8s.Tests
|
||||
{
|
||||
// here watcher is ready to use, but http server has not responsed yet.
|
||||
created.Set();
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Assert.True(eventsReceived.IsSet);
|
||||
@@ -128,20 +128,20 @@ namespace k8s.Tests
|
||||
httpContext.Response.StatusCode = (int)HttpStatusCode.OK;
|
||||
httpContext.Response.ContentLength = null;
|
||||
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse);
|
||||
await WriteStreamLine(httpContext, MockBadStreamLine);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await WriteStreamLine(httpContext, MockBadStreamLine);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockBadStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockBadStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false);
|
||||
|
||||
// make server alive, cannot set to int.max as of it would block response
|
||||
await serverShutdown.WaitAsync();
|
||||
await serverShutdown.WaitAsync().ConfigureAwait(false);
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() });
|
||||
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false);
|
||||
|
||||
var events = new HashSet<WatchEventType>();
|
||||
var errors = 0;
|
||||
@@ -164,7 +164,7 @@ namespace k8s.Tests
|
||||
onClosed: connectionClosed.Set);
|
||||
|
||||
// wait server yields all events
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
|
||||
Assert.True(
|
||||
eventsReceived.CurrentCount == 0,
|
||||
@@ -180,7 +180,7 @@ namespace k8s.Tests
|
||||
// Let the server know it can initiate a shut down.
|
||||
serverShutdown.Set();
|
||||
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
Assert.True(connectionClosed.IsSet);
|
||||
}
|
||||
}
|
||||
@@ -194,11 +194,11 @@ namespace k8s.Tests
|
||||
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse);
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false);
|
||||
|
||||
while (serverRunning)
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -206,7 +206,7 @@ namespace k8s.Tests
|
||||
{
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() });
|
||||
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false);
|
||||
|
||||
var events = new HashSet<WatchEventType>();
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace k8s.Tests
|
||||
onClosed: connectionClosed.Set);
|
||||
|
||||
// wait at least an event
|
||||
await Task.WhenAny(Task.Run(() => eventsReceived.Wait()), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(Task.Run(() => eventsReceived.Wait()), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
Assert.True(
|
||||
eventsReceived.CurrentCount == 0,
|
||||
"Timed out waiting for events.");
|
||||
@@ -256,19 +256,19 @@ namespace k8s.Tests
|
||||
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false);
|
||||
|
||||
// make server alive, cannot set to int.max as of it would block response
|
||||
await serverShutdown.WaitAsync();
|
||||
await serverShutdown.WaitAsync().ConfigureAwait(false);
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() });
|
||||
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false);
|
||||
|
||||
var events = new HashSet<WatchEventType>();
|
||||
var errors = 0;
|
||||
@@ -291,7 +291,7 @@ namespace k8s.Tests
|
||||
onClosed: waitForClosed.Set);
|
||||
|
||||
// wait server yields all events
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
|
||||
Assert.True(
|
||||
eventsReceived.CurrentCount == 0,
|
||||
@@ -308,7 +308,7 @@ namespace k8s.Tests
|
||||
|
||||
serverShutdown.Set();
|
||||
|
||||
await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
Assert.True(waitForClosed.IsSet);
|
||||
Assert.False(watcher.Watching);
|
||||
}
|
||||
@@ -323,21 +323,21 @@ namespace k8s.Tests
|
||||
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse);
|
||||
await Task.Delay(TimeSpan.FromSeconds(120)); // The default timeout is 100 seconds
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine);
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false);
|
||||
await Task.Delay(TimeSpan.FromSeconds(120)).ConfigureAwait(false); // The default timeout is 100 seconds
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false);
|
||||
|
||||
// make server alive, cannot set to int.max as of it would block response
|
||||
await serverShutdown.WaitAsync();
|
||||
await serverShutdown.WaitAsync().ConfigureAwait(false);
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() });
|
||||
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false);
|
||||
|
||||
var events = new HashSet<WatchEventType>();
|
||||
var errors = 0;
|
||||
@@ -360,7 +360,7 @@ namespace k8s.Tests
|
||||
onClosed: connectionClosed.Set);
|
||||
|
||||
// wait server yields all events
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
|
||||
Assert.True(
|
||||
eventsReceived.CurrentCount == 0,
|
||||
@@ -377,7 +377,7 @@ namespace k8s.Tests
|
||||
|
||||
serverShutdown.Set();
|
||||
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
Assert.True(connectionClosed.IsSet);
|
||||
}
|
||||
}
|
||||
@@ -392,14 +392,14 @@ namespace k8s.Tests
|
||||
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse);
|
||||
await waitForException.WaitAsync();
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false);
|
||||
await waitForException.WaitAsync().ConfigureAwait(false);
|
||||
throw new IOException("server down");
|
||||
}))
|
||||
{
|
||||
var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() });
|
||||
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false);
|
||||
|
||||
waitForException.Set();
|
||||
Watcher<V1Pod> watcher;
|
||||
@@ -413,13 +413,13 @@ namespace k8s.Tests
|
||||
onClosed: waitForClosed.Set);
|
||||
|
||||
// wait server down
|
||||
await Task.WhenAny(exceptionReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(exceptionReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
|
||||
Assert.True(
|
||||
exceptionReceived.IsSet,
|
||||
"Timed out waiting for exception");
|
||||
|
||||
await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
Assert.True(waitForClosed.IsSet);
|
||||
Assert.False(watcher.Watching);
|
||||
Assert.IsType<IOException>(exceptionCatched);
|
||||
@@ -446,11 +446,11 @@ namespace k8s.Tests
|
||||
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await WriteStreamLine(httpContext, MockKubeApiServer.MockPodResponse).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
|
||||
// make server alive, cannot set to int.max as of it would block response
|
||||
await serverShutdown.WaitAsync();
|
||||
await serverShutdown.WaitAsync().ConfigureAwait(false);
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
@@ -463,7 +463,7 @@ namespace k8s.Tests
|
||||
Assert.False(handler1.Called);
|
||||
Assert.False(handler2.Called);
|
||||
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true);
|
||||
var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true).ConfigureAwait(false);
|
||||
|
||||
var events = new HashSet<WatchEventType>();
|
||||
|
||||
@@ -475,7 +475,7 @@ namespace k8s.Tests
|
||||
});
|
||||
|
||||
// wait server yields all events
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
|
||||
Assert.True(
|
||||
eventsReceived.CurrentCount == 0,
|
||||
@@ -499,13 +499,13 @@ namespace k8s.Tests
|
||||
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine);
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false);
|
||||
|
||||
// make server alive, cannot set to int.max as of it would block response
|
||||
await serverShutdown.WaitAsync();
|
||||
await serverShutdown.WaitAsync().ConfigureAwait(false);
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
@@ -533,10 +533,10 @@ namespace k8s.Tests
|
||||
errors += 1;
|
||||
eventsReceived.Signal();
|
||||
},
|
||||
onClosed: connectionClosed.Set);
|
||||
onClosed: connectionClosed.Set).ConfigureAwait(false);
|
||||
|
||||
// wait server yields all events
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
|
||||
Assert.True(
|
||||
eventsReceived.CurrentCount == 0,
|
||||
@@ -553,7 +553,7 @@ namespace k8s.Tests
|
||||
|
||||
serverShutdown.Set();
|
||||
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
Assert.True(connectionClosed.IsSet);
|
||||
}
|
||||
}
|
||||
@@ -584,19 +584,19 @@ namespace k8s.Tests
|
||||
{
|
||||
Image = "ubuntu/xenial",
|
||||
Name = "runner",
|
||||
Command = new List<string>() {"/bin/bash", "-c", "--" },
|
||||
Command = new List<string>() { "/bin/bash", "-c", "--" },
|
||||
Args = new List<string>()
|
||||
{
|
||||
"trap : TERM INT; sleep infinity & wait"
|
||||
}
|
||||
}
|
||||
"trap : TERM INT; sleep infinity & wait",
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy = "Never"
|
||||
RestartPolicy = "Never",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"default");
|
||||
"default").ConfigureAwait(false);
|
||||
|
||||
Collection<Tuple<WatchEventType, V1Job>> events = new Collection<Tuple<WatchEventType, V1Job>>();
|
||||
|
||||
@@ -618,15 +618,15 @@ namespace k8s.Tests
|
||||
},
|
||||
onClosed: connectionClosed.Set).ConfigureAwait(false);
|
||||
|
||||
await started.WaitAsync();
|
||||
await started.WaitAsync().ConfigureAwait(false);
|
||||
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TimeSpan.FromMinutes(3)));
|
||||
await Task.WhenAny(connectionClosed.WaitAsync(), Task.Delay(TimeSpan.FromMinutes(3))).ConfigureAwait(false);
|
||||
Assert.True(connectionClosed.IsSet);
|
||||
|
||||
await kubernetes.DeleteNamespacedJobAsync(
|
||||
job.Metadata.Name,
|
||||
job.Metadata.NamespaceProperty,
|
||||
new V1DeleteOptions());
|
||||
new V1DeleteOptions()).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[Fact(Skip = "https://github.com/kubernetes-client/csharp/issues/165")]
|
||||
@@ -637,14 +637,14 @@ namespace k8s.Tests
|
||||
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(120)); // The default timeout is 100 seconds
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine);
|
||||
await Task.Delay(TimeSpan.FromSeconds(120)).ConfigureAwait(false); // The default timeout is 100 seconds
|
||||
await WriteStreamLine(httpContext, MockAddedEventStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockDeletedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockModifiedStreamLine).ConfigureAwait(false);
|
||||
await WriteStreamLine(httpContext, MockErrorStreamLine).ConfigureAwait(false);
|
||||
|
||||
// make server alive, cannot set to int.max as of it would block response
|
||||
await serverShutdown.WaitAsync();
|
||||
await serverShutdown.WaitAsync().ConfigureAwait(false);
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
@@ -671,10 +671,10 @@ namespace k8s.Tests
|
||||
|
||||
errors += 1;
|
||||
eventsReceived.Signal();
|
||||
});
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
// wait server yields all events
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout));
|
||||
await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)).ConfigureAwait(false);
|
||||
|
||||
Assert.True(
|
||||
eventsReceived.CurrentCount == 0,
|
||||
@@ -701,8 +701,8 @@ namespace k8s.Tests
|
||||
using (var server = new MockKubeApiServer(testOutput, async httpContext =>
|
||||
{
|
||||
httpContext.Response.StatusCode = 200;
|
||||
await httpContext.Response.Body.FlushAsync();
|
||||
await Task.Delay(TimeSpan.FromSeconds(5)); // The default timeout is 100 seconds
|
||||
await httpContext.Response.Body.FlushAsync().ConfigureAwait(false);
|
||||
await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(false); // The default timeout is 100 seconds
|
||||
|
||||
return true;
|
||||
}, resp: ""))
|
||||
@@ -715,8 +715,8 @@ namespace k8s.Tests
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () =>
|
||||
{
|
||||
await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true,
|
||||
cancellationToken: cts.Token);
|
||||
});
|
||||
cancellationToken: cts.Token).ConfigureAwait(false);
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace k8s.Tests
|
||||
/// <summary>
|
||||
/// The next server port to use.
|
||||
/// </summary>
|
||||
static int NextPort = 13255;
|
||||
|
||||
private static int nextPort = 13255;
|
||||
private bool disposedValue;
|
||||
private readonly ITestOutputHelper testOutput;
|
||||
|
||||
/// <summary>
|
||||
@@ -38,7 +38,7 @@ namespace k8s.Tests
|
||||
{
|
||||
this.testOutput = testOutput;
|
||||
|
||||
int port = Interlocked.Increment(ref NextPort);
|
||||
int port = Interlocked.Increment(ref nextPort);
|
||||
|
||||
// Useful to diagnose test timeouts.
|
||||
TestCancellation.Register(
|
||||
@@ -199,7 +199,7 @@ namespace k8s.Tests
|
||||
await serverSocket.CloseAsync(
|
||||
received.Result.CloseStatus.Value,
|
||||
received.Result.CloseStatusDescription,
|
||||
TestCancellation);
|
||||
TestCancellation).ConfigureAwait(false);
|
||||
|
||||
testOutput.WriteLine("Server socket closed.");
|
||||
}
|
||||
@@ -260,7 +260,7 @@ namespace k8s.Tests
|
||||
|
||||
await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Binary,
|
||||
endOfMessage: true,
|
||||
cancellationToken: TestCancellation);
|
||||
cancellationToken: TestCancellation).ConfigureAwait(false);
|
||||
|
||||
return sendBuffer.Length;
|
||||
}
|
||||
@@ -289,7 +289,7 @@ namespace k8s.Tests
|
||||
using (MemoryStream buffer = new MemoryStream())
|
||||
{
|
||||
byte[] receiveBuffer = new byte[1024];
|
||||
WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation);
|
||||
WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation).ConfigureAwait(false);
|
||||
if (receiveResult.MessageType != WebSocketMessageType.Binary)
|
||||
{
|
||||
throw new IOException(
|
||||
@@ -300,7 +300,7 @@ namespace k8s.Tests
|
||||
|
||||
while (!receiveResult.EndOfMessage)
|
||||
{
|
||||
receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation);
|
||||
receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation).ConfigureAwait(false);
|
||||
buffer.Write(receiveBuffer, 0, receiveResult.Count);
|
||||
}
|
||||
|
||||
@@ -315,11 +315,7 @@ namespace k8s.Tests
|
||||
totalBytes: receivedData.Length);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
this.CancellationSource.Dispose();
|
||||
this.Host.Dispose();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ServiceClientCredentials"/> implementation representing no credentials (i.e. anonymous).
|
||||
@@ -335,7 +331,7 @@ namespace k8s.Tests
|
||||
/// <summary>
|
||||
/// Create new <see cref="AnonymousClientCredentials"/>.
|
||||
/// </summary>
|
||||
AnonymousClientCredentials()
|
||||
private AnonymousClientCredentials()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -348,7 +344,35 @@ namespace k8s.Tests
|
||||
/// <summary>
|
||||
/// An error occurred while closing the server-side socket.
|
||||
/// </summary>
|
||||
static readonly EventId ErrorClosingServerSocket = new EventId(1000, nameof(ErrorClosingServerSocket));
|
||||
private static readonly EventId ErrorClosingServerSocket = new EventId(1000, nameof(ErrorClosingServerSocket));
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
CancellationSource.Dispose();
|
||||
Host.Dispose();
|
||||
}
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
|
||||
// ~WebSocketTestBase()
|
||||
// {
|
||||
// // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
// Dispose(disposing: false);
|
||||
// }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(disposing: true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ kind: Namespace
|
||||
metadata:
|
||||
name: ns";
|
||||
|
||||
var types = new Dictionary<String, Type>();
|
||||
var types = new Dictionary<string, Type>();
|
||||
types.Add("v1/Pod", typeof(V1Pod));
|
||||
types.Add("v1/Namespace", typeof(V1Namespace));
|
||||
|
||||
@@ -157,15 +157,15 @@ metadata:
|
||||
{
|
||||
new V1VolumeMount
|
||||
{
|
||||
Name = "vm1", MountPath = "/vm1", ReadOnlyProperty = true
|
||||
Name = "vm1", MountPath = "/vm1", ReadOnlyProperty = true,
|
||||
},
|
||||
new V1VolumeMount
|
||||
{
|
||||
Name = "vm2", MountPath = "/vm2", ReadOnlyProperty = false
|
||||
Name = "vm2", MountPath = "/vm2", ReadOnlyProperty = false,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -284,7 +284,7 @@ spec:
|
||||
ApiVersion = "v1",
|
||||
Spec = new V1ServiceSpec
|
||||
{
|
||||
Ports = new List<V1ServicePort> { new V1ServicePort { Port = 3000, TargetPort = 3000 } }
|
||||
Ports = new List<V1ServicePort> { new V1ServicePort { Port = 3000, TargetPort = 3000 } },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -336,8 +336,8 @@ data:
|
||||
";
|
||||
|
||||
var result = Yaml.LoadFromString<V1Secret>(kManifest);
|
||||
Assert.Equal(Encoding.UTF8.GetString(result.Data["username"]), "bXktYXBw");
|
||||
Assert.Equal(Encoding.UTF8.GetString(result.Data["password"]), "Mzk1MjgkdmRnN0pi");
|
||||
Assert.Equal("bXktYXBw", Encoding.UTF8.GetString(result.Data["username"]));
|
||||
Assert.Equal("Mzk1MjgkdmRnN0pi", Encoding.UTF8.GetString(result.Data["password"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user