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:
Boshi Lian
2020-10-23 08:31:57 -07:00
committed by GitHub
parent 0d6882316c
commit e38525c13b
65 changed files with 1350 additions and 617 deletions

View File

@@ -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();

View File

@@ -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();

View File

@@ -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);

View File

@@ -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());
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>

View File

@@ -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

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>();
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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>

View File

@@ -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-]+$");
}
}

View 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);
}
}
}

View 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));
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -306,6 +306,7 @@ namespace k8s
{
throw new ArgumentNullException(nameof(config));
}
if (config.TokenProvider != null)
{
return new TokenCredentials(config.TokenProvider);

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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),
};
}

View File

@@ -5,6 +5,7 @@ namespace k8s.Models
/// <summary>
/// Describes object type in Kubernetes
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class KubernetesEntityAttribute : Attribute
{
/// <summary>

View File

@@ -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

View File

@@ -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}";
}
}
}

View 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);
}
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
}
}

View File

@@ -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
{

View 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);
}
}
}

View 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}";
}
}
}

View File

@@ -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,
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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");

View 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);
}
}
}

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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();
}
}
}

View File

@@ -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 };

View File

@@ -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);
}

View File

@@ -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"]);

View File

@@ -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");
}

View File

@@ -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>

View File

@@ -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);

View File

@@ -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

View File

@@ -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)));

View File

@@ -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.

View File

@@ -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); })

View File

@@ -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);
}
}
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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
{

View File

@@ -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).

View File

@@ -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);

View File

@@ -7,6 +7,6 @@ namespace k8s.Tests
{
Windows = 1,
Linux = 2,
OSX = 4
OSX = 4,
}
}

View File

@@ -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" },
},
},
};

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View File

@@ -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");
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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"]));
}
}
}