diff --git a/Directory.Build.targets b/Directory.Build.targets index 0c7844991..b9fbd9494 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -8,4 +8,8 @@ All + + + + diff --git a/examples/attach/Attach.cs b/examples/attach/Attach.cs index e37e211b6..dafefe3d4 100755 --- a/examples/attach/Attach.cs +++ b/examples/attach/Attach.cs @@ -23,7 +23,9 @@ private static async Task Main(string[] args) private async static Task AttachToPod(IKubernetes client, V1Pod pod) { - var webSocket = await client.WebSocketNamespacedPodAttachAsync(pod.Metadata.Name, "default", pod.Spec.Containers[0].Name); + var webSocket = + await client.WebSocketNamespacedPodAttachAsync(pod.Metadata.Name, "default", + pod.Spec.Containers[0].Name); var demux = new StreamDemuxer(webSocket); demux.Start(); diff --git a/examples/exec/Exec.cs b/examples/exec/Exec.cs index 66e490454..b0355892d 100755 --- a/examples/exec/Exec.cs +++ b/examples/exec/Exec.cs @@ -20,7 +20,9 @@ private static async Task Main(string[] args) private async static Task ExecInPod(IKubernetes client, V1Pod pod) { - var webSocket = await client.WebSocketNamespacedPodExecAsync(pod.Metadata.Name, "default", "ls", pod.Spec.Containers[0].Name); + var webSocket = + await client.WebSocketNamespacedPodExecAsync(pod.Metadata.Name, "default", "ls", + pod.Spec.Containers[0].Name); var demux = new StreamDemuxer(webSocket); demux.Start(); diff --git a/examples/httpClientFactory/PodListHostedService.cs b/examples/httpClientFactory/PodListHostedService.cs index 3b2c94214..66f61e8bd 100644 --- a/examples/httpClientFactory/PodListHostedService.cs +++ b/examples/httpClientFactory/PodListHostedService.cs @@ -28,6 +28,7 @@ public async Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation(item.Metadata.Name); } + if (list.Items.Count == 0) { _logger.LogInformation("Empty!"); diff --git a/examples/httpClientFactory/Program.cs b/examples/httpClientFactory/Program.cs index db34e6bac..48477f808 100644 --- a/examples/httpClientFactory/Program.cs +++ b/examples/httpClientFactory/Program.cs @@ -12,10 +12,7 @@ public static async Task Main(string[] args) { // Learn more about generic hosts at https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host using (var host = new HostBuilder() - .ConfigureLogging((logging) => - { - logging.AddConsole(); - }) + .ConfigureLogging((logging) => { logging.AddConsole(); }) .ConfigureServices((hostBuilderContext, services) => { // Ideally this config would be read from the .net core config constructs, diff --git a/examples/labels/PodList.cs b/examples/labels/PodList.cs index 3fbc89997..89d701ff0 100755 --- a/examples/labels/PodList.cs +++ b/examples/labels/PodList.cs @@ -21,11 +21,13 @@ private static void Main(string[] args) { continue; } + var labels = new List(); foreach (var key in item.Spec.Selector) { labels.Add(key.Key + "=" + key.Value); } + var labelStr = string.Join(",", labels.ToArray()); Console.WriteLine(labelStr); var podList = client.ListNamespacedPod("default", labelSelector: labelStr); @@ -33,10 +35,12 @@ private static void Main(string[] args) { Console.WriteLine(pod.Metadata.Name); } + if (podList.Items.Count == 0) { Console.WriteLine("Empty!"); } + Console.WriteLine(); } } diff --git a/examples/logs/Logs.cs b/examples/logs/Logs.cs index c8f5a22c6..d21dbb734 100755 --- a/examples/logs/Logs.cs +++ b/examples/logs/Logs.cs @@ -19,9 +19,11 @@ private static async Task Main(string[] args) Console.WriteLine("No pods!"); return; } + var pod = list.Items[0]; - var response = await client.ReadNamespacedPodLogWithHttpMessagesAsync(pod.Metadata.Name, pod.Metadata.NamespaceProperty, follow: true); + var response = await client.ReadNamespacedPodLogWithHttpMessagesAsync(pod.Metadata.Name, + pod.Metadata.NamespaceProperty, follow: true); var stream = response.Body; stream.CopyTo(Console.OpenStandardOutput()); } diff --git a/examples/namespace/Namespace.cs b/examples/namespace/Namespace.cs index c5094180a..a7db12e2c 100644 --- a/examples/namespace/Namespace.cs +++ b/examples/namespace/Namespace.cs @@ -15,6 +15,7 @@ static void ListNamespaces(IKubernetes client) { Console.WriteLine(item.Metadata.Name); } + if (list.Items.Count == 0) { Console.WriteLine("Empty!"); @@ -41,6 +42,7 @@ static async Task DeleteAsync(IKubernetes client, string name, int delayMillis) { return; } + throw ex; } } @@ -51,6 +53,7 @@ static async Task DeleteAsync(IKubernetes client, string name, int delayMillis) { return; } + throw ex; } } @@ -68,13 +71,7 @@ private static void Main(string[] args) ListNamespaces(client); - var ns = new V1Namespace - { - Metadata = new V1ObjectMeta - { - Name = "test" - } - }; + var ns = new V1Namespace { Metadata = new V1ObjectMeta { Name = "test" } }; var result = client.CreateNamespace(ns); Console.WriteLine(result); diff --git a/examples/patch/Program.cs b/examples/patch/Program.cs index 5a80cd2e0..2298538cc 100644 --- a/examples/patch/Program.cs +++ b/examples/patch/Program.cs @@ -20,10 +20,7 @@ private static void Main(string[] args) var name = pod.Metadata.Name; PrintLabels(pod); - var newlabels = new Dictionary(pod.Metadata.Labels) - { - ["test"] = "test" - }; + var newlabels = new Dictionary(pod.Metadata.Labels) { ["test"] = "test" }; var patch = new JsonPatchDocument(); patch.Replace(e => e.Metadata.Labels, newlabels); client.PatchNamespacedPod(new V1Patch(patch), name, "default"); @@ -38,6 +35,7 @@ private static void PrintLabels(V1Pod pod) { Console.WriteLine($"{k} : {v}"); } + Console.WriteLine("=-=-=-=-=-=-=-=-=-=-="); } } diff --git a/examples/simple/PodList.cs b/examples/simple/PodList.cs index 557c0b778..54f36e91d 100755 --- a/examples/simple/PodList.cs +++ b/examples/simple/PodList.cs @@ -16,6 +16,7 @@ private static void Main(string[] args) { Console.WriteLine(item.Metadata.Name); } + if (list.Items.Count == 0) { Console.WriteLine("Empty!"); diff --git a/gen/KubernetesWatchGenerator/Program.cs b/gen/KubernetesWatchGenerator/Program.cs index 18b8f5acb..ac7114792 100644 --- a/gen/KubernetesWatchGenerator/Program.cs +++ b/gen/KubernetesWatchGenerator/Program.cs @@ -49,10 +49,16 @@ static async Task Main(string[] args) swagger = await SwaggerDocument.FromFileAsync(Path.Combine(args[1], "swagger.json.unprocessed")); _schemaToNameMap = swagger.Definitions.ToDictionary(x => x.Value, x => x.Key); _schemaDefinitionsInMultipleGroups = _schemaToNameMap.Values.Select(x => - { - var parts = x.Split("."); - return new { FullName = x, Name = parts[parts.Length - 1], Version = parts[parts.Length - 2], Group = parts[parts.Length - 3] }; - }) + { + var parts = x.Split("."); + return new + { + FullName = x, + Name = parts[parts.Length - 1], + Version = parts[parts.Length - 2], + Group = parts[parts.Length - 3], + }; + }) .GroupBy(x => new { x.Name, x.Version }) .Where(x => x.Count() > 1) .SelectMany(x => x) @@ -61,7 +67,15 @@ static async Task Main(string[] args) _classNameToPluralMap = swagger.Operations .Where(x => x.Operation.OperationId.StartsWith("list")) - .Select(x => { return new { PluralName = x.Path.Split("/").Last(), ClassName = GetClassNameForSchemaDefinition(x.Operation.Responses["200"].ActualResponseSchema) }; }) + .Select(x => + { + return new + { + PluralName = x.Path.Split("/").Last(), + ClassName = GetClassNameForSchemaDefinition(x.Operation.Responses["200"] + .ActualResponseSchema), + }; + }) .Distinct() .ToDictionary(x => x.ClassName, x => x.PluralName); @@ -75,7 +89,6 @@ static async Task Main(string[] args) .ToDictionary(x => x.Key, x => x.Value); - // Register helpers used in the templating. Helpers.Register(nameof(ToXmlDoc), ToXmlDoc); Helpers.Register(nameof(GetClassName), GetClassName); @@ -92,30 +105,27 @@ static async Task Main(string[] args) // Generate the Watcher operations // We skip operations where the name of the class in the C# client could not be determined correctly. // That's usually because there are different version of the same object (e.g. for deployments). - var blacklistedOperations = new HashSet() - { - }; + var blacklistedOperations = new HashSet() { }; var watchOperations = swagger.Operations.Where( o => o.Path.Contains("/watch/") - && o.Operation.ActualParameters.Any(p => p.Name == "name") - && !blacklistedOperations.Contains(o.Operation.OperationId)).ToArray(); + && o.Operation.ActualParameters.Any(p => p.Name == "name") + && !blacklistedOperations.Contains(o.Operation.OperationId)).ToArray(); // Render. - Render.FileToFile("IKubernetes.Watch.cs.template", watchOperations, Path.Combine(outputDirectory, "IKubernetes.Watch.cs")); - Render.FileToFile("Kubernetes.Watch.cs.template", watchOperations, Path.Combine(outputDirectory, "Kubernetes.Watch.cs")); + Render.FileToFile("IKubernetes.Watch.cs.template", watchOperations, + Path.Combine(outputDirectory, "IKubernetes.Watch.cs")); + Render.FileToFile("Kubernetes.Watch.cs.template", watchOperations, + Path.Combine(outputDirectory, "Kubernetes.Watch.cs")); // Generate the interface declarations - var skippedTypes = new HashSet() - { - "V1WatchEvent", - }; + var skippedTypes = new HashSet() { "V1WatchEvent", }; var definitions = swagger.Definitions.Values .Where( d => d.ExtensionData != null - && d.ExtensionData.ContainsKey("x-kubernetes-group-version-kind") - && !skippedTypes.Contains(GetClassName(d))); + && d.ExtensionData.ContainsKey("x-kubernetes-group-version-kind") + && !skippedTypes.Contains(GetClassName(d))); var modelsDir = Path.Combine(outputDirectory, "Models"); _classesWithValidation = Directory.EnumerateFiles(modelsDir) @@ -124,10 +134,12 @@ static async Task Main(string[] args) .Select(x => x.Class) .ToHashSet(); - Render.FileToFile("ModelExtensions.cs.template", definitions, Path.Combine(outputDirectory, "ModelExtensions.cs")); + Render.FileToFile("ModelExtensions.cs.template", definitions, + Path.Combine(outputDirectory, "ModelExtensions.cs")); } - static void ToXmlDoc(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void ToXmlDoc(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is string) { @@ -147,13 +159,15 @@ static void ToXmlDoc(RenderContext context, IList arguments, IDictionary { first = false; } + context.Write(line); } } } } - static void GetClassName(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetClassName(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerOperation) { @@ -167,7 +181,8 @@ static void GetClassName(RenderContext context, IList arguments, IDictio static string GetClassName(SwaggerOperation watchOperation) { - var groupVersionKind = (Dictionary)watchOperation.ExtensionData["x-kubernetes-group-version-kind"]; + var groupVersionKind = + (Dictionary)watchOperation.ExtensionData["x-kubernetes-group-version-kind"]; return GetClassName(groupVersionKind); } @@ -187,20 +202,23 @@ private static string GetClassName(JsonSchema4 definition) return GetClassName(groupVersionKind); } - private static void GetInterfaceName(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) - { + private static void GetInterfaceName(RenderContext context, IList arguments, + IDictionary options, RenderBlock fn, RenderBlock inverse) + { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) { context.Write(GetInterfaceName(arguments[0] as JsonSchema4)); } - } static string GetClassNameForSchemaDefinition(JsonSchema4 definition) { - if (definition.ExtensionData != null && definition.ExtensionData.ContainsKey("x-kubernetes-group-version-kind")) + if (definition.ExtensionData != null && + definition.ExtensionData.ContainsKey("x-kubernetes-group-version-kind")) + { return GetClassName(definition); + } var schemaName = _schemaToNameMap[definition]; @@ -209,11 +227,14 @@ static string GetClassNameForSchemaDefinition(JsonSchema4 definition) var version = parts[parts.Length - 2]; var entityName = parts[parts.Length - 1]; if (!_schemaDefinitionsInMultipleGroups.Contains(schemaName)) - group = null; + { + @group = null; + } + var className = ToPascalCase($"{group}{version}{entityName}"); return className; - } + static string GetInterfaceName(JsonSchema4 definition) { var groupVersionKindElements = (object[])definition.ExtensionData["x-kubernetes-group-version-kind"]; @@ -235,7 +256,9 @@ static string GetInterfaceName(JsonSchema4 definition) if (definition.Properties.TryGetValue("items", out var itemsProperty)) { - var schema = itemsProperty.Type == JsonObjectType.Object ? itemsProperty.Reference : itemsProperty.Item.Reference; + var schema = itemsProperty.Type == JsonObjectType.Object + ? itemsProperty.Reference + : itemsProperty.Item.Reference; interfaces.Add($"IItems<{GetClassNameForSchemaDefinition(schema)}>"); } @@ -245,13 +268,17 @@ static string GetInterfaceName(JsonSchema4 definition) } if (_classesWithValidation.Contains(className)) + { interfaces.Add("IValidate"); + } + var result = string.Join(", ", interfaces); return result; } - static void GetKind(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetKind(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) { @@ -267,15 +294,20 @@ private static string GetKind(JsonSchema4 definition) return groupVersionKind["kind"] as string; } - static void GetPlural(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetPlural(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) { var plural = GetPlural(arguments[0] as JsonSchema4); if (plural != null) + { context.Write($"\"{plural}\""); + } else + { context.Write("null"); + } } } @@ -285,7 +317,8 @@ private static string GetPlural(JsonSchema4 definition) return _classNameToPluralMap.GetValueOrDefault(className, null); } - static void GetGroup(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetGroup(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) { @@ -301,7 +334,8 @@ private static string GetGroup(JsonSchema4 definition) return groupVersionKind["group"] as string; } - static void GetMethodName(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetMethodName(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerOperation) { @@ -322,14 +356,17 @@ static string GetMethodName(SwaggerOperation watchOperation) return methodName; } - static void GetDotNetType(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetDotNetType(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerParameter) { var parameter = arguments[0] as SwaggerParameter; context.Write(GetDotNetType(parameter.Type, parameter.Name, parameter.IsRequired)); } - else if (arguments != null && arguments.Count > 2 && arguments[0] != null && arguments[1] != null && arguments[2] != null && arguments[0] is JsonObjectType && arguments[1] is string && arguments[2] is bool) + else if (arguments != null && arguments.Count > 2 && arguments[0] != null && arguments[1] != null && + arguments[2] != null && arguments[0] is JsonObjectType && arguments[1] is string && + arguments[2] is bool) { context.Write(GetDotNetType((JsonObjectType)arguments[0], (string)arguments[1], (bool)arguments[2])); } @@ -380,7 +417,8 @@ private static string GetDotNetType(JsonObjectType jsonType, string name, bool r } } - static void GetDotNetName(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetDotNetName(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerParameter) { @@ -408,9 +446,11 @@ private static string GetDotNetName(string jsonName) return jsonName; } - static void GetPathExpression(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetPathExpression(RenderContext context, IList arguments, + IDictionary options, RenderBlock fn, RenderBlock inverse) { - if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is SwaggerOperationDescription) + if (arguments != null && arguments.Count > 0 && arguments[0] != null && + arguments[0] is SwaggerOperationDescription) { var operation = arguments[0] as SwaggerOperationDescription; context.Write(GetPathExpression(operation)); @@ -430,7 +470,8 @@ private static string GetPathExpression(SwaggerOperationDescription operation) return pathExpression; } - static void GetApiVersion(RenderContext context, IList arguments, IDictionary options, RenderBlock fn, RenderBlock inverse) + static void GetApiVersion(RenderContext context, IList arguments, IDictionary options, + RenderBlock fn, RenderBlock inverse) { if (arguments != null && arguments.Count > 0 && arguments[0] != null && arguments[0] is JsonSchema4) { diff --git a/kubernetes-client.ruleset b/kubernetes-client.ruleset index bafbb4ec1..2853cab0e 100644 --- a/kubernetes-client.ruleset +++ b/kubernetes-client.ruleset @@ -4,5 +4,10 @@ + + + + + diff --git a/src/KubernetesClient/ByteBuffer.cs b/src/KubernetesClient/ByteBuffer.cs index 7e3106d8a..8b5d25ed4 100644 --- a/src/KubernetesClient/ByteBuffer.cs +++ b/src/KubernetesClient/ByteBuffer.cs @@ -78,20 +78,12 @@ public int MaximumSize /// /// Gets the offset from which the next byte will be read. Increased every time a caller reads data. /// - public int ReadWaterMark - { - get; - private set; - } + public int ReadWaterMark { get; private set; } /// /// Gets the offset to which the next byte will be written. Increased every time a caller writes data. /// - public int WriteWaterMark - { - get; - private set; - } + public int WriteWaterMark { get; private set; } /// /// Gets the amount of bytes availble for reading. @@ -192,7 +184,8 @@ public void Write(byte[] data, int offset, int length) if (length > availableBeforeWrapping) { - Array.Copy(data, offset + availableBeforeWrapping, this.buffer, 0, length - availableBeforeWrapping); + Array.Copy(data, offset + availableBeforeWrapping, this.buffer, 0, + length - availableBeforeWrapping); this.WriteWaterMark = length - availableBeforeWrapping; } @@ -256,7 +249,8 @@ public int Read(byte[] data, int offset, int count) if (toRead > availableBeforeWrapping) { - Array.Copy(this.buffer, 0, data, offset + availableBeforeWrapping, toRead - availableBeforeWrapping); + Array.Copy(this.buffer, 0, data, offset + availableBeforeWrapping, + toRead - availableBeforeWrapping); this.ReadWaterMark = toRead - availableBeforeWrapping; } diff --git a/src/KubernetesClient/CertUtils.cs b/src/KubernetesClient/CertUtils.cs index 42ff3b662..9e3bbf880 100644 --- a/src/KubernetesClient/CertUtils.cs +++ b/src/KubernetesClient/CertUtils.cs @@ -49,6 +49,7 @@ public static X509Certificate2 GeneratePfx(KubernetesClientConfiguration config) { keyData = Convert.FromBase64String(config.ClientCertificateKeyData); } + if (!string.IsNullOrWhiteSpace(config.ClientKeyFilePath)) { keyData = File.ReadAllBytes(config.ClientKeyFilePath); @@ -63,6 +64,7 @@ public static X509Certificate2 GeneratePfx(KubernetesClientConfiguration config) { certData = Convert.FromBase64String(config.ClientCertificateData); } + if (!string.IsNullOrWhiteSpace(config.ClientCertificateFilePath)) { certData = File.ReadAllBytes(config.ClientCertificateFilePath); @@ -82,6 +84,7 @@ public static X509Certificate2 GeneratePfx(KubernetesClientConfiguration config) "Client certificates must be marked for digital signing. " + "See https://github.com/kubernetes-client/csharp/issues/319"); } + object obj; using (var reader = new StreamReader(new MemoryStream(keyData))) { diff --git a/src/KubernetesClient/ChannelIndex.cs b/src/KubernetesClient/ChannelIndex.cs index 92313ff49..1d2445ed0 100644 --- a/src/KubernetesClient/ChannelIndex.cs +++ b/src/KubernetesClient/ChannelIndex.cs @@ -32,6 +32,6 @@ public enum ChannelIndex : byte /// has a Width and Height property. /// /// - Resize + Resize, } } diff --git a/src/KubernetesClient/Exceptions/KubeConfigException.cs b/src/KubernetesClient/Exceptions/KubeConfigException.cs index 7a93295e1..f9d9b0627 100644 --- a/src/KubernetesClient/Exceptions/KubeConfigException.cs +++ b/src/KubernetesClient/Exceptions/KubeConfigException.cs @@ -12,12 +12,12 @@ public KubeConfigException() } public KubeConfigException(string message) - : base(message) + : base(message) { } public KubeConfigException(string message, Exception inner) - : base(message, inner) + : base(message, inner) { } } diff --git a/src/KubernetesClient/Exceptions/KubernetesClientException.cs b/src/KubernetesClient/Exceptions/KubernetesClientException.cs index c2b9547b6..9f2344bad 100644 --- a/src/KubernetesClient/Exceptions/KubernetesClientException.cs +++ b/src/KubernetesClient/Exceptions/KubernetesClientException.cs @@ -12,12 +12,12 @@ public KubernetesClientException() } public KubernetesClientException(string message) - : base(message) + : base(message) { } public KubernetesClientException(string message, Exception inner) - : base(message, inner) + : base(message, inner) { } } diff --git a/src/KubernetesClient/IKubernetes.Exec.cs b/src/KubernetesClient/IKubernetes.Exec.cs index 316fd629a..76ea8a012 100644 --- a/src/KubernetesClient/IKubernetes.Exec.cs +++ b/src/KubernetesClient/IKubernetes.Exec.cs @@ -30,6 +30,7 @@ public partial interface IKubernetes /// /// A which represents the asynchronous operation. /// - Task NamespacedPodExecAsync(string name, string @namespace, string container, IEnumerable command, bool tty, ExecAsyncCallback action, CancellationToken cancellationToken); + Task NamespacedPodExecAsync(string name, string @namespace, string container, IEnumerable command, + bool tty, ExecAsyncCallback action, CancellationToken cancellationToken); } } diff --git a/src/KubernetesClient/IKubernetes.Watch.cs b/src/KubernetesClient/IKubernetes.Watch.cs index e8d85e4e8..eebc03d2b 100644 --- a/src/KubernetesClient/IKubernetes.Watch.cs +++ b/src/KubernetesClient/IKubernetes.Watch.cs @@ -54,6 +54,11 @@ public partial interface IKubernetes /// /// A which represents the asynchronous operation, and returns a new watcher. /// - Task> WatchObjectAsync(string path, string @continue = null, string fieldSelector = null, bool? includeUninitialized = null, string labelSelector = null, int? limit = null, bool? pretty = null, int? timeoutSeconds = null, string resourceVersion = null, Dictionary> customHeaders = null, Action onEvent = null, Action onError = null, Action onClosed = null, CancellationToken cancellationToken = default(CancellationToken)); + Task> WatchObjectAsync(string path, string @continue = null, string fieldSelector = null, + bool? includeUninitialized = null, string labelSelector = null, int? limit = null, bool? pretty = null, + int? timeoutSeconds = null, string resourceVersion = null, + Dictionary> customHeaders = null, Action onEvent = null, + Action onError = null, Action onClosed = null, + CancellationToken cancellationToken = default(CancellationToken)); } } diff --git a/src/KubernetesClient/IKubernetes.WebSocket.cs b/src/KubernetesClient/IKubernetes.WebSocket.cs index 68eb7d703..fdd2be5af 100644 --- a/src/KubernetesClient/IKubernetes.WebSocket.cs +++ b/src/KubernetesClient/IKubernetes.WebSocket.cs @@ -56,7 +56,10 @@ public partial interface IKubernetes /// /// A which can be used to communicate with the process running in the pod. /// - Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", string command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true, string webSocketSubProtol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", + string command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, + bool tty = true, string webSocketSubProtol = null, Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)); /// /// Executes a command in a pod. @@ -107,7 +110,11 @@ public partial interface IKubernetes /// /// A which can be used to communicate with the process running in the pod. /// - Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", IEnumerable command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true, string webSocketSubProtol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", + IEnumerable command = null, string container = null, bool stderr = true, bool stdin = true, + bool stdout = true, bool tty = true, string webSocketSubProtol = null, + Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)); /// /// Executes a command in a pod. @@ -158,7 +165,12 @@ public partial interface IKubernetes /// /// A which can be used to communicate with the process running in the pod. /// - Task MuxedStreamNamespacedPodExecAsync(string name, string @namespace = "default", IEnumerable command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true, string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + Task MuxedStreamNamespacedPodExecAsync(string name, string @namespace = "default", + IEnumerable command = null, string container = null, bool stderr = true, bool stdin = true, + bool stdout = true, bool tty = true, + string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol, + Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)); /// /// Start port forwarding one or more ports of a pod. @@ -182,7 +194,9 @@ public partial interface IKubernetes /// /// The cancellation token. /// - Task WebSocketNamespacedPodPortForwardAsync(string name, string @namespace, IEnumerable ports, string webSocketSubProtocol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + Task WebSocketNamespacedPodPortForwardAsync(string name, string @namespace, IEnumerable ports, + string webSocketSubProtocol = null, Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)); /// /// connect GET requests to attach of Pod @@ -239,6 +253,9 @@ public partial interface IKubernetes /// /// A response object containing the response body and response headers. /// - Task WebSocketNamespacedPodAttachAsync(string name, string @namespace, string container = default(string), bool stderr = true, bool stdin = false, bool stdout = true, bool tty = false, string webSocketSubProtol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)); + Task WebSocketNamespacedPodAttachAsync(string name, string @namespace, + string container = default(string), bool stderr = true, bool stdin = false, bool stdout = true, + bool tty = false, string webSocketSubProtol = null, Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)); } } diff --git a/src/KubernetesClient/IStreamDemuxer.cs b/src/KubernetesClient/IStreamDemuxer.cs index d3534920a..ddf5d9f92 100644 --- a/src/KubernetesClient/IStreamDemuxer.cs +++ b/src/KubernetesClient/IStreamDemuxer.cs @@ -74,7 +74,8 @@ public interface IStreamDemuxer : IDisposable /// /// A which represents the asynchronous operation. /// - Task Write(ChannelIndex index, byte[] buffer, int offset, int count, CancellationToken cancellationToken = default(CancellationToken)); + Task Write(ChannelIndex index, byte[] buffer, int offset, int count, + CancellationToken cancellationToken = default(CancellationToken)); /// /// Directly writes data to a channel. @@ -97,6 +98,7 @@ public interface IStreamDemuxer : IDisposable /// /// A which represents the asynchronous operation. /// - Task Write(byte index, byte[] buffer, int offset, int count, CancellationToken cancellationToken = default(CancellationToken)); + Task Write(byte index, byte[] buffer, int offset, int count, + CancellationToken cancellationToken = default(CancellationToken)); } } diff --git a/src/KubernetesClient/IValidate.cs b/src/KubernetesClient/IValidate.cs index 85adeab60..c81f553f2 100644 --- a/src/KubernetesClient/IValidate.cs +++ b/src/KubernetesClient/IValidate.cs @@ -9,6 +9,5 @@ public interface IValidate /// Validate the object. /// void Validate(); - } } diff --git a/src/KubernetesClient/IntstrIntOrString.cs b/src/KubernetesClient/IntstrIntOrString.cs index 3c61c81c6..be0b3442d 100644 --- a/src/KubernetesClient/IntstrIntOrString.cs +++ b/src/KubernetesClient/IntstrIntOrString.cs @@ -24,6 +24,7 @@ public object ReadYaml(IParser parser, Type type) { return null; } + return new IntstrIntOrString(scalar.Value); } finally @@ -31,6 +32,7 @@ public object ReadYaml(IParser parser, Type type) parser.MoveNext(); } } + throw new InvalidOperationException(parser.Current?.ToString()); } @@ -98,9 +100,21 @@ protected bool Equals(IntstrIntOrString other) public override bool Equals(object obj) { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != this.GetType()) + { + return false; + } + return Equals((IntstrIntOrString)obj); } diff --git a/src/KubernetesClient/KubeConfigModels/AuthProvider.cs b/src/KubernetesClient/KubeConfigModels/AuthProvider.cs index 4194cfcc7..8ab4f8782 100644 --- a/src/KubernetesClient/KubeConfigModels/AuthProvider.cs +++ b/src/KubernetesClient/KubeConfigModels/AuthProvider.cs @@ -20,6 +20,5 @@ public class AuthProvider /// [YamlMember(Alias = "config")] public Dictionary Config { get; set; } - } } diff --git a/src/KubernetesClient/KubeConfigModels/ExecCredentialResponse.cs b/src/KubernetesClient/KubeConfigModels/ExecCredentialResponse.cs index 0c353fb7d..78c3bed21 100644 --- a/src/KubernetesClient/KubeConfigModels/ExecCredentialResponse.cs +++ b/src/KubernetesClient/KubeConfigModels/ExecCredentialResponse.cs @@ -5,11 +5,8 @@ namespace k8s.KubeConfigModels { public class ExecCredentialResponse { - [JsonProperty("apiVersion")] - public string ApiVersion { get; set; } - [JsonProperty("kind")] - public string Kind { get; set; } - [JsonProperty("status")] - public IDictionary Status { get; set; } + [JsonProperty("apiVersion")] public string ApiVersion { get; set; } + [JsonProperty("kind")] public string Kind { get; set; } + [JsonProperty("status")] public IDictionary Status { get; set; } } } diff --git a/src/KubernetesClient/KubeConfigModels/ExternalExecution.cs b/src/KubernetesClient/KubeConfigModels/ExternalExecution.cs index 899f519ee..ffd1fa568 100644 --- a/src/KubernetesClient/KubeConfigModels/ExternalExecution.cs +++ b/src/KubernetesClient/KubeConfigModels/ExternalExecution.cs @@ -5,18 +5,20 @@ namespace k8s.KubeConfigModels { public class ExternalExecution { - [YamlMember(Alias = "apiVersion")] - public string ApiVersion { get; set; } + [YamlMember(Alias = "apiVersion")] public string ApiVersion { get; set; } + /// /// The command to execute. Required. /// [YamlMember(Alias = "command")] public string Command { get; set; } + /// /// Environment variables to set when executing the plugin. Optional. /// [YamlMember(Alias = "env")] public IDictionary EnvironmentVariables { get; set; } + /// /// Arguments to pass when executing the plugin. Optional. /// diff --git a/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs b/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs index 980d93a52..18eb9d647 100644 --- a/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs +++ b/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs @@ -19,11 +19,9 @@ public class K8SConfiguration [YamlMember(Alias = "preferences")] public IDictionary Preferences { get; set; } - [YamlMember(Alias = "apiVersion")] - public string ApiVersion { get; set; } + [YamlMember(Alias = "apiVersion")] public string ApiVersion { get; set; } - [YamlMember(Alias = "kind")] - public string Kind { get; set; } + [YamlMember(Alias = "kind")] public string Kind { get; set; } /// /// Gets or sets the name of the context that you would like to use by default. diff --git a/src/KubernetesClient/Kubernetes.ConfigInit.cs b/src/KubernetesClient/Kubernetes.ConfigInit.cs index 3a2172521..fc2629377 100644 --- a/src/KubernetesClient/Kubernetes.ConfigInit.cs +++ b/src/KubernetesClient/Kubernetes.ConfigInit.cs @@ -38,7 +38,8 @@ public Kubernetes(KubernetesClientConfiguration config, HttpClient httpClient) : /// /// Whether or not the object should own the lifetime of . /// - public Kubernetes(KubernetesClientConfiguration config, HttpClient httpClient, bool disposeHttpClient) : this(httpClient, disposeHttpClient) + public Kubernetes(KubernetesClientConfiguration config, HttpClient httpClient, bool disposeHttpClient) : this( + httpClient, disposeHttpClient) { ValidateConfig(config); CaCerts = config.SslCaCerts; @@ -94,10 +95,11 @@ private void InitializeFromConfig(KubernetesClientConfiguration config) if (config.SkipTlsVerify) { #if NET452 - ((WebRequestHandler) HttpClientHandler).ServerCertificateValidationCallback = + ((WebRequestHandler)HttpClientHandler).ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; #elif XAMARINIOS1_0 || MONOANDROID8_1 - System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => + System.Net.ServicePointManager.ServerCertificateValidationCallback += + (sender, certificate, chain, sslPolicyErrors) => { return true; }; @@ -113,14 +115,17 @@ private void InitializeFromConfig(KubernetesClientConfiguration config) throw new KubeConfigException("A CA must be set when SkipTlsVerify === false"); } #if NET452 - ((WebRequestHandler) HttpClientHandler).ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + ((WebRequestHandler)HttpClientHandler).ServerCertificateValidationCallback = + (sender, certificate, chain, sslPolicyErrors) => { return Kubernetes.CertificateValidationCallBack(sender, CaCerts, certificate, chain, sslPolicyErrors); }; #elif XAMARINIOS1_0 - System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => + System.Net.ServicePointManager.ServerCertificateValidationCallback += + (sender, certificate, chain, sslPolicyErrors) => { - var cert = new X509Certificate2(certificate); + var cert + = new X509Certificate2(certificate); return Kubernetes.CertificateValidationCallBack(sender, CaCerts, cert, chain, sslPolicyErrors); }; #elif MONOANDROID8_1 @@ -128,22 +133,28 @@ private void InitializeFromConfig(KubernetesClientConfiguration config) foreach (X509Certificate2 caCert in CaCerts) { - using (var certStream = new System.IO.MemoryStream(caCert.RawData)) + using (var certStream + = new System.IO.MemoryStream(caCert.RawData)) { - Java.Security.Cert.Certificate cert = Java.Security.Cert.CertificateFactory.GetInstance("X509").GenerateCertificate(certStream); + Java.Security.Cert.Certificate cert + = Java.Security.Cert.CertificateFactory.GetInstance("X509").GenerateCertificate(certStream); certList.Add(cert); } } - var handler = (Xamarin.Android.Net.AndroidClientHandler)this.HttpClientHandler; + var handler + = (Xamarin.Android.Net.AndroidClientHandler)this.HttpClientHandler; - handler.TrustedCerts = certList; + handler.TrustedCerts + = certList; #else - HttpClientHandler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => - { - return Kubernetes.CertificateValidationCallBack(sender, CaCerts, certificate, chain, sslPolicyErrors); - }; + HttpClientHandler.ServerCertificateCustomValidationCallback = + (sender, certificate, chain, sslPolicyErrors) => + { + return Kubernetes.CertificateValidationCallBack(sender, CaCerts, certificate, chain, + sslPolicyErrors); + }; #endif } } @@ -159,7 +170,7 @@ private void InitializeFromConfig(KubernetesClientConfiguration config) partial void CustomInitialize() { -#if NET452 +#if NET452 ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; #endif DeserializationSettings.Converters.Add(new V1Status.V1StatusObjectViewConverter()); @@ -168,7 +179,9 @@ partial void CustomInitialize() /// A that simply forwards a request with no further processing. private sealed class ForwardingHandler : DelegatingHandler { - public ForwardingHandler(HttpMessageHandler handler) : base(handler) { } + public ForwardingHandler(HttpMessageHandler handler) : base(handler) + { + } } private void AppendDelegatingHandler() where T : DelegatingHandler, new() @@ -183,10 +196,7 @@ public ForwardingHandler(HttpMessageHandler handler) : base(handler) { } { // last one // append watcher handler between to last handler - cur.InnerHandler = new T - { - InnerHandler = cur.InnerHandler - }; + cur.InnerHandler = new T { InnerHandler = cur.InnerHandler }; break; } @@ -211,11 +221,16 @@ private void CreateHttpClient(DelegatingHandler[] handlers) for (int i = handlers.Length - 1; i >= 0; i--) { DelegatingHandler handler = handlers[i]; - while (handler.InnerHandler is DelegatingHandler d) handler = d; + while (handler.InnerHandler is DelegatingHandler d) + { + handler = d; + } + handler.InnerHandler = FirstMessageHandler; FirstMessageHandler = handlers[i]; } } + AppendDelegatingHandler(); HttpClient = new HttpClient(FirstMessageHandler, false); } @@ -287,7 +302,11 @@ public static bool CertificateValidationCallBack( /// public static ServiceClientCredentials CreateCredentials(KubernetesClientConfiguration config) { - if (config == null) throw new ArgumentNullException(nameof(config)); + if (config == null) + { + throw new ArgumentNullException(nameof(config)); + } + if (!string.IsNullOrEmpty(config.AccessToken)) { return new TokenCredentials(config.AccessToken); @@ -296,6 +315,7 @@ public static ServiceClientCredentials CreateCredentials(KubernetesClientConfigu { return new BasicAuthenticationCredentials() { UserName = config.Username, Password = config.Password }; } + return null; } } diff --git a/src/KubernetesClient/Kubernetes.Exec.cs b/src/KubernetesClient/Kubernetes.Exec.cs index 5868e5924..d8856c79d 100644 --- a/src/KubernetesClient/Kubernetes.Exec.cs +++ b/src/KubernetesClient/Kubernetes.Exec.cs @@ -12,7 +12,8 @@ namespace k8s { public partial class Kubernetes { - public async Task NamespacedPodExecAsync(string name, string @namespace, string container, IEnumerable command, bool tty, ExecAsyncCallback action, CancellationToken cancellationToken) + public async Task NamespacedPodExecAsync(string name, string @namespace, string container, + IEnumerable command, bool tty, ExecAsyncCallback action, CancellationToken cancellationToken) { // All other parameters are being validated by MuxedStreamNamespacedPodExecAsync if (action == null) @@ -22,7 +23,9 @@ public async Task NamespacedPodExecAsync(string name, string @namespace, st try { - using (var muxedStream = await this.MuxedStreamNamespacedPodExecAsync(name: name, @namespace: @namespace, command: command, container: container, tty: tty, cancellationToken: cancellationToken).ConfigureAwait(false)) + using (var muxedStream = await this.MuxedStreamNamespacedPodExecAsync(name: name, + @namespace: @namespace, command: command, container: container, tty: tty, + cancellationToken: cancellationToken).ConfigureAwait(false)) using (Stream stdIn = muxedStream.GetStream(null, ChannelIndex.StdIn)) using (Stream stdOut = muxedStream.GetStream(ChannelIndex.StdOut, null)) using (Stream stdErr = muxedStream.GetStream(ChannelIndex.StdErr, null)) diff --git a/src/KubernetesClient/Kubernetes.Watch.cs b/src/KubernetesClient/Kubernetes.Watch.cs index edd2e99f3..d0d65e1d2 100644 --- a/src/KubernetesClient/Kubernetes.Watch.cs +++ b/src/KubernetesClient/Kubernetes.Watch.cs @@ -13,7 +13,12 @@ namespace k8s public partial class Kubernetes { /// - public async Task> WatchObjectAsync(string path, string @continue = null, string fieldSelector = null, bool? includeUninitialized = null, string labelSelector = null, int? limit = null, bool? pretty = null, int? timeoutSeconds = null, string resourceVersion = null, Dictionary> customHeaders = null, Action onEvent = null, Action onError = null, Action onClosed = null, CancellationToken cancellationToken = default(CancellationToken)) + public async Task> WatchObjectAsync(string path, string @continue = null, + string fieldSelector = null, bool? includeUninitialized = null, string labelSelector = null, + int? limit = null, bool? pretty = null, int? timeoutSeconds = null, string resourceVersion = null, + Dictionary> customHeaders = null, Action onEvent = null, + Action onError = null, Action onClosed = null, + CancellationToken cancellationToken = default(CancellationToken)) { // Tracing bool _shouldTrace = ServiceClientTracing.IsEnabled; @@ -59,7 +64,8 @@ public partial class Kubernetes if (includeUninitialized != null) { - Utilities.AddQueryParameter(query, "includeUninitialized", includeUninitialized.Value ? "true" : "false"); + Utilities.AddQueryParameter(query, "includeUninitialized", + includeUninitialized.Value ? "true" : "false"); } if (!string.IsNullOrEmpty(labelSelector)) @@ -87,7 +93,11 @@ public partial class Kubernetes Utilities.AddQueryParameter(query, "resourceVersion", resourceVersion); } - uriBuilder.Query = query.Length == 0 ? "" : query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it + uriBuilder.Query = + query.Length == 0 + ? "" + : query.ToString(1, + query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it // Create HTTP transport objects var httpRequest = new HttpRequestMessage(HttpMethod.Get, uriBuilder.ToString()); @@ -120,7 +130,9 @@ public partial class Kubernetes } cancellationToken.ThrowIfCancellationRequested(); - var httpResponse = await HttpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var httpResponse = await HttpClient + .SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken) + .ConfigureAwait(false); if (_shouldTrace) { @@ -133,7 +145,8 @@ public partial class Kubernetes { string responseContent = string.Empty; - var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", httpResponse.StatusCode)); + var ex = new HttpOperationException(string.Format("Operation returned an invalid status code '{0}'", + httpResponse.StatusCode)); if (httpResponse.Content != null) { responseContent = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false); diff --git a/src/KubernetesClient/Kubernetes.WebSocket.cs b/src/KubernetesClient/Kubernetes.WebSocket.cs index 8b7a97a6c..25d57b89f 100644 --- a/src/KubernetesClient/Kubernetes.WebSocket.cs +++ b/src/KubernetesClient/Kubernetes.WebSocket.cs @@ -27,21 +27,37 @@ public partial class Kubernetes public Func CreateWebSocketBuilder { get; set; } = () => new WebSocketBuilder(); /// - public Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", string command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true, string webSocketSubProtol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + public Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", + string command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, + bool tty = true, string webSocketSubProtol = null, Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)) { - return WebSocketNamespacedPodExecAsync(name, @namespace, new string[] { command }, container, stderr, stdin, stdout, tty, webSocketSubProtol, customHeaders, cancellationToken); + return WebSocketNamespacedPodExecAsync(name, @namespace, new string[] { command }, container, stderr, stdin, + stdout, tty, webSocketSubProtol, customHeaders, cancellationToken); } /// - public virtual async Task MuxedStreamNamespacedPodExecAsync(string name, string @namespace = "default", IEnumerable command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true, string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task MuxedStreamNamespacedPodExecAsync(string name, + string @namespace = "default", IEnumerable command = null, string container = null, + bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true, + string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol, + Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)) { - WebSocket webSocket = await this.WebSocketNamespacedPodExecAsync(name: name, @namespace: @namespace, command: command, container: container, tty: tty, cancellationToken: cancellationToken).ConfigureAwait(false); + WebSocket webSocket = await this.WebSocketNamespacedPodExecAsync(name: name, @namespace: @namespace, + command: command, container: container, tty: tty, cancellationToken: cancellationToken) + .ConfigureAwait(false); StreamDemuxer muxer = new StreamDemuxer(webSocket); return muxer; } /// - public virtual Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", IEnumerable command = null, string container = null, bool stderr = true, bool stdin = true, bool stdout = true, bool tty = true, string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + public virtual Task WebSocketNamespacedPodExecAsync(string name, string @namespace = "default", + IEnumerable command = null, string container = null, bool stderr = true, bool stdin = true, + bool stdout = true, bool tty = true, + string webSocketSubProtol = WebSocketProtocol.V4BinaryWebsocketProtocol, + Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)) { if (name == null) { @@ -68,7 +84,8 @@ public partial class Kubernetes { if (c.Length > 0 && c[0] == 0xfeff) { - throw new InvalidOperationException($"Detected an attempt to execute a command which starts with a Unicode byte order mark (BOM). This is probably incorrect. The command was {c}"); + throw new InvalidOperationException( + $"Detected an attempt to execute a command which starts with a Unicode byte order mark (BOM). This is probably incorrect. The command was {c}"); } } @@ -89,7 +106,8 @@ public partial class Kubernetes tracingParameters.Add("tty", tty); tracingParameters.Add("webSocketSubProtol", webSocketSubProtol); tracingParameters.Add("cancellationToken", cancellationToken); - ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodExecAsync), tracingParameters); + ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodExecAsync), + tracingParameters); } // Construct URL @@ -115,17 +133,25 @@ public partial class Kubernetes Utilities.AddQueryParameter(query, "container", container); } - query.Append("&stderr=").Append(stderr ? '1' : '0'); // the query string is guaranteed not to be empty here because it has a 'command' param + query.Append("&stderr=") + .Append(stderr + ? '1' + : '0'); // the query string is guaranteed not to be empty here because it has a 'command' param query.Append("&stdin=").Append(stdin ? '1' : '0'); query.Append("&stdout=").Append(stdout ? '1' : '0'); query.Append("&tty=").Append(tty ? '1' : '0'); - uriBuilder.Query = query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it + 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, cancellationToken); + return this.StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtol, customHeaders, + cancellationToken); } /// - public Task WebSocketNamespacedPodPortForwardAsync(string name, string @namespace, IEnumerable ports, string webSocketSubProtocol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + public Task WebSocketNamespacedPodPortForwardAsync(string name, string @namespace, + IEnumerable ports, string webSocketSubProtocol = null, + Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)) { if (name == null) { @@ -154,7 +180,8 @@ public partial class Kubernetes tracingParameters.Add("ports", ports); tracingParameters.Add("webSocketSubProtocol", webSocketSubProtocol); tracingParameters.Add("cancellationToken", cancellationToken); - ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodPortForwardAsync), tracingParameters); + ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodPortForwardAsync), + tracingParameters); } // Construct URL @@ -171,16 +198,25 @@ public partial class Kubernetes var q = new StringBuilder(); foreach (var port in ports) { - if (q.Length != 0) q.Append('&'); + if (q.Length != 0) + { + q.Append('&'); + } + q.Append("ports=").Append(port.ToString(CultureInfo.InvariantCulture)); } + uriBuilder.Query = q.ToString(); - return StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtocol, customHeaders, cancellationToken); + return StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtocol, customHeaders, + cancellationToken); } /// - public Task WebSocketNamespacedPodAttachAsync(string name, string @namespace, string container = default(string), bool stderr = true, bool stdin = false, bool stdout = true, bool tty = false, string webSocketSubProtol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + public Task WebSocketNamespacedPodAttachAsync(string name, string @namespace, + string container = default(string), bool stderr = true, bool stdin = false, bool stdout = true, + bool tty = false, string webSocketSubProtol = null, Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)) { if (name == null) { @@ -208,7 +244,8 @@ public partial class Kubernetes tracingParameters.Add("tty", tty); tracingParameters.Add("webSocketSubProtol", webSocketSubProtol); tracingParameters.Add("cancellationToken", cancellationToken); - ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodAttachAsync), tracingParameters); + ServiceClientTracing.Enter(_invocationId, this, nameof(WebSocketNamespacedPodAttachAsync), + tracingParameters); } // Construct URL @@ -228,12 +265,16 @@ public partial class Kubernetes query.Append("&stdout=").Append(stdout ? '1' : '0'); query.Append("&tty=").Append(tty ? '1' : '0'); Utilities.AddQueryParameter(query, "container", container); - uriBuilder.Query = query.ToString(1, query.Length - 1); // UriBuilder.Query doesn't like leading '?' chars, so trim it + 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, cancellationToken); + return StreamConnectAsync(uriBuilder.Uri, _invocationId, webSocketSubProtol, customHeaders, + cancellationToken); } - protected async Task StreamConnectAsync(Uri uri, string invocationId = null, string webSocketSubProtocol = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken)) + protected async Task StreamConnectAsync(Uri uri, string invocationId = null, + string webSocketSubProtocol = null, Dictionary> customHeaders = null, + CancellationToken cancellationToken = default(CancellationToken)) { bool _shouldTrace = ServiceClientTracing.IsEnabled; @@ -301,9 +342,13 @@ public partial class Kubernetes WebSocket webSocket = null; try { - webSocket = await webSocketBuilder.BuildAndConnectAsync(uri, CancellationToken.None).ConfigureAwait(false); + webSocket = await webSocketBuilder.BuildAndConnectAsync(uri, CancellationToken.None) + .ConfigureAwait(false); } - catch (WebSocketException wse) when (wse.WebSocketErrorCode == WebSocketError.HeaderError || (wse.InnerException is WebSocketException && ((WebSocketException)wse.InnerException).WebSocketErrorCode == WebSocketError.HeaderError)) + catch (WebSocketException wse) when (wse.WebSocketErrorCode == WebSocketError.HeaderError || + (wse.InnerException is WebSocketException && + ((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. @@ -332,11 +377,13 @@ public partial class Kubernetes status = SafeJsonConvert.DeserializeObject(content); } - var ex = new HttpOperationException($"The operation returned an invalid status code: {response.StatusCode}", wse) - { - Response = new HttpResponseMessageWrapper(response, content), - Body = status != null ? (object)status : content, - }; + var ex = + new HttpOperationException( + $"The operation returned an invalid status code: {response.StatusCode}", wse) + { + Response = new HttpResponseMessageWrapper(response, content), + Body = status != null ? (object)status : content, + }; response.Dispose(); @@ -362,15 +409,18 @@ public partial class Kubernetes #if (NET452 || NETSTANDARD2_0) if (this.CaCerts != null) { - webSocketBuilder.CleanupServerCertificateValidationCallback(this.ServerCertificateValidationCallback); + webSocketBuilder.CleanupServerCertificateValidationCallback( + this.ServerCertificateValidationCallback); } #endif } + return webSocket; } #if (NET452 || NETSTANDARD2_0) - internal bool ServerCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) + internal bool ServerCertificateValidationCallback(object sender, X509Certificate certificate, X509Chain chain, + SslPolicyErrors sslPolicyErrors) { return Kubernetes.CertificateValidationCallBack(sender, this.CaCerts, certificate, chain, sslPolicyErrors); } diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs index 47e174d0a..668dd3ae0 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs @@ -49,7 +49,8 @@ public static KubernetesClientConfiguration BuildDefaultConfig() var kubeconfig = Environment.GetEnvironmentVariable(KubeConfigEnvironmentVariable); if (kubeconfig != null) { - var configList = kubeconfig.Split(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ';' : ':').Select((s) => new FileInfo(s)); + var configList = kubeconfig.Split(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ';' : ':') + .Select((s) => new FileInfo(s)); var k8sConfig = LoadKubeConfig(configList.ToArray()); return BuildConfigFromConfigObject(k8sConfig); } @@ -95,7 +96,8 @@ public static KubernetesClientConfiguration BuildConfigFromConfigFile(string kub public static KubernetesClientConfiguration BuildConfigFromConfigFile(FileInfo kubeconfig, string currentContext = null, string masterUrl = null, bool useRelativePaths = true) { - return BuildConfigFromConfigFileAsync(kubeconfig, currentContext, masterUrl, useRelativePaths).GetAwaiter().GetResult(); + return BuildConfigFromConfigFileAsync(kubeconfig, currentContext, masterUrl, useRelativePaths).GetAwaiter() + .GetResult(); } /// @@ -106,7 +108,6 @@ public static KubernetesClientConfiguration BuildConfigFromConfigFile(FileInfo k /// override the kube api server endpoint, set null if do not want to override /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig /// file is located. When , the paths will be considered to be relative to the current working directory. - public static async Task BuildConfigFromConfigFileAsync(FileInfo kubeconfig, string currentContext = null, string masterUrl = null, bool useRelativePaths = true) { @@ -166,10 +167,12 @@ public static async Task BuildConfigFromConfigFil /// A , for example loaded from /// Override the current context in config, set null if do not want to override /// Override the Kubernetes API server endpoint, set null if do not want to override - public static KubernetesClientConfiguration BuildConfigFromConfigObject(K8SConfiguration k8SConfig, string currentContext = null, string masterUrl = null) + public static KubernetesClientConfiguration BuildConfigFromConfigObject(K8SConfiguration k8SConfig, + string currentContext = null, string masterUrl = null) => GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig); - private static KubernetesClientConfiguration GetKubernetesClientConfiguration(string currentContext, string masterUrl, K8SConfiguration k8SConfig) + private static KubernetesClientConfiguration GetKubernetesClientConfiguration(string currentContext, + string masterUrl, K8SConfiguration k8SConfig) { var k8SConfiguration = new KubernetesClientConfiguration(); @@ -179,6 +182,7 @@ private static KubernetesClientConfiguration GetKubernetesClientConfiguration(st { k8SConfiguration.InitializeContext(k8SConfig, currentContext); } + if (!string.IsNullOrWhiteSpace(masterUrl)) { k8SConfiguration.Host = masterUrl; @@ -237,6 +241,7 @@ private void SetClusterDetails(K8SConfiguration k8SConfig, Context activeContext { throw new KubeConfigException($"Cluster not found for context `{activeContext}` in kubeconfig"); } + if (string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.Server)) { throw new KubeConfigException($"Server not found for current-context `{activeContext}` in kubeconfig"); @@ -259,7 +264,8 @@ private void SetClusterDetails(K8SConfiguration k8SConfig, Context activeContext } else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) { - SslCaCerts = new X509Certificate2Collection(new X509Certificate2(GetFullPath(k8SConfig, clusterDetails.ClusterEndpoint.CertificateAuthority))); + SslCaCerts = new X509Certificate2Collection(new X509Certificate2(GetFullPath(k8SConfig, + clusterDetails.ClusterEndpoint.CertificateAuthority))); } } } @@ -293,7 +299,7 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) userCredentialsFound = true; } else if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.UserName) && - !string.IsNullOrWhiteSpace(userDetails.UserCredentials.Password)) + !string.IsNullOrWhiteSpace(userDetails.UserCredentials.Password)) { Username = userDetails.UserCredentials.UserName; Password = userDetails.UserCredentials.Password; @@ -320,7 +326,7 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) if (userDetails.UserCredentials.AuthProvider != null) { if (userDetails.UserCredentials.AuthProvider.Config != null - && userDetails.UserCredentials.AuthProvider.Config.ContainsKey("access-token")) + && userDetails.UserCredentials.AuthProvider.Config.ContainsKey("access-token")) { switch (userDetails.UserCredentials.AuthProvider.Name) { @@ -332,24 +338,25 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) var expiresOn = Int32.Parse(config["expires-on"]); DateTimeOffset expires; #if NET452 - var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); - expires = epoch.AddSeconds(expiresOn); + var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); + expires + = epoch.AddSeconds(expiresOn); #else expires = DateTimeOffset.FromUnixTimeSeconds(expiresOn); #endif if (DateTimeOffset.Compare(expires - , DateTimeOffset.Now) - <= 0) + , 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); + , clientId + , apiServerId + , refresh); config["access-token"] = newToken; } } @@ -365,11 +372,11 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) if (config.ContainsKey(keyExpire)) { if (DateTimeOffset.TryParse(config[keyExpire] - , out DateTimeOffset expires)) + , out DateTimeOffset expires)) { if (DateTimeOffset.Compare(expires - , DateTimeOffset.Now) - <= 0) + , DateTimeOffset.Now) + <= 0) { throw new KubeConfigException("Refresh not supported."); } @@ -388,10 +395,15 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) if (userDetails.UserCredentials.ExternalExecution != null) { if (string.IsNullOrWhiteSpace(userDetails.UserCredentials.ExternalExecution.Command)) + { throw new KubeConfigException( "External command execution to receive user credentials must include a command to execute"); + } + if (string.IsNullOrWhiteSpace(userDetails.UserCredentials.ExternalExecution.ApiVersion)) + { throw new KubeConfigException("External command execution missing ApiVersion key"); + } var token = ExecuteExternalCommand(userDetails.UserCredentials.ExternalExecution); AccessToken = token; @@ -426,12 +438,9 @@ public static string ExecuteExternalCommand(ExternalExecution config) { var execInfo = new Dictionary { - {"apiVersion", config.ApiVersion}, - {"kind", "ExecCredentials"}, - {"spec", new Dictionary - { - {"interactive", Environment.UserInteractive} - }} + {"apiVersion", config.ApiVersion }, + {"kind", "ExecCredentials" }, + {"spec", new Dictionary {{"interactive", Environment.UserInteractive } } }, }; var process = new Process(); @@ -440,13 +449,20 @@ public static string ExecuteExternalCommand(ExternalExecution config) JsonConvert.SerializeObject(execInfo)); if (config.EnvironmentVariables != null) + { foreach (var configEnvironmentVariableKey in config.EnvironmentVariables.Keys) + { process.StartInfo.Environment.Add(key: configEnvironmentVariableKey, value: config.EnvironmentVariables[configEnvironmentVariableKey]); + } + } process.StartInfo.FileName = config.Command; if (config.Arguments != null) + { process.StartInfo.Arguments = string.Join(" ", config.Arguments); + } + process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.UseShellExecute = false; @@ -463,7 +479,9 @@ public static string ExecuteExternalCommand(ExternalExecution config) var stdout = process.StandardOutput.ReadToEnd(); var stderr = process.StandardOutput.ReadToEnd(); if (string.IsNullOrWhiteSpace(stderr) == false) + { throw new KubeConfigException($"external exec failed due to: {stderr}"); + } // Wait for a maximum of 5 seconds, if a response takes longer probably something went wrong... process.WaitForExit(5); @@ -472,8 +490,11 @@ public static string ExecuteExternalCommand(ExternalExecution config) { var responseObject = JsonConvert.DeserializeObject(stdout); if (responseObject == null || responseObject.ApiVersion != config.ApiVersion) + { throw new KubeConfigException( $"external exec failed because api version {responseObject.ApiVersion} does not match {config.ApiVersion}"); + } + return responseObject.Status["token"]; } catch (JsonSerializationException ex) @@ -484,9 +505,6 @@ public static string ExecuteExternalCommand(ExternalExecution config) { throw new KubeConfigException($"external exec failed due to uncaught exception: {ex}"); } - - - } #endif @@ -497,7 +515,8 @@ public static string ExecuteExternalCommand(ExternalExecution config) /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig /// file is located. When , the paths will be considered to be relative to the current working directory. /// Instance of the class - public static async Task LoadKubeConfigAsync(string kubeconfigPath = null, bool useRelativePaths = true) + public static async Task LoadKubeConfigAsync(string kubeconfigPath = null, + bool useRelativePaths = true) { var fileInfo = new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation); @@ -523,7 +542,8 @@ public static K8SConfiguration LoadKubeConfig(string kubeconfigPath = null, bool /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig /// file is located. When , the paths will be considered to be relative to the current working directory. /// Instance of the class - public static async Task LoadKubeConfigAsync(FileInfo kubeconfig, bool useRelativePaths = true) + public static async Task LoadKubeConfigAsync(FileInfo kubeconfig, + bool useRelativePaths = true) { if (!kubeconfig.Exists) { @@ -602,7 +622,8 @@ internal static K8SConfiguration LoadKubeConfig(FileInfo[] kubeConfigs, bool use /// The kube config files will be merges into a single , where first occurence wins. /// See https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/#merging-kubeconfig-files. /// - internal static async Task LoadKubeConfigAsync(FileInfo[] kubeConfigs, bool useRelativePaths = true) + internal static async Task LoadKubeConfigAsync(FileInfo[] kubeConfigs, + bool useRelativePaths = true) { var basek8SConfig = await LoadKubeConfigAsync(kubeConfigs[0], useRelativePaths).ConfigureAwait(false); @@ -659,7 +680,8 @@ private static void MergeKubeConfig(K8SConfiguration basek8SConfig, K8SConfigura // Kinds must match in kube config, otherwise throw. if (basek8SConfig.Kind != mergek8SConfig.Kind) { - throw new KubeConfigException($"kubeconfig \"kind\" are different between {basek8SConfig.FileName} and {mergek8SConfig.FileName}"); + throw new KubeConfigException( + $"kubeconfig \"kind\" are different between {basek8SConfig.FileName} and {mergek8SConfig.FileName}"); } if (mergek8SConfig.Preferences != null) @@ -691,7 +713,8 @@ private static void MergeKubeConfig(K8SConfiguration basek8SConfig, K8SConfigura basek8SConfig.Contexts = MergeLists(basek8SConfig.Contexts, mergek8SConfig.Contexts, (s) => s.Name); } - private static IEnumerable MergeLists(IEnumerable baseList, IEnumerable mergeList, Func getNameFunc) + private static IEnumerable MergeLists(IEnumerable baseList, IEnumerable mergeList, + Func getNameFunc) { if (mergeList != null && mergeList.Count() > 0) { diff --git a/src/KubernetesClient/KubernetesClientConfiguration.HttpClientHandler.cs b/src/KubernetesClient/KubernetesClientConfiguration.HttpClientHandler.cs index 6c6560732..89f258bcf 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.HttpClientHandler.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.HttpClientHandler.cs @@ -21,10 +21,12 @@ public HttpClientHandler CreateDefaultHttpClientHandler() } else { - httpClientHandler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyErrors) => - { - return Kubernetes.CertificateValidationCallBack(sender, this.SslCaCerts, certificate, chain, sslPolicyErrors); - }; + httpClientHandler.ServerCertificateCustomValidationCallback = + (sender, certificate, chain, sslPolicyErrors) => + { + return Kubernetes.CertificateValidationCallBack(sender, this.SslCaCerts, certificate, chain, + sslPolicyErrors); + }; } } #endif @@ -37,14 +39,14 @@ public HttpClientHandler CreateDefaultHttpClientHandler() public void AddCertificates(HttpClientHandler handler) { if ((!string.IsNullOrWhiteSpace(this.ClientCertificateData) || - !string.IsNullOrWhiteSpace(this.ClientCertificateFilePath)) && - (!string.IsNullOrWhiteSpace(this.ClientCertificateKeyData) || - !string.IsNullOrWhiteSpace(this.ClientKeyFilePath))) + !string.IsNullOrWhiteSpace(this.ClientCertificateFilePath)) && + (!string.IsNullOrWhiteSpace(this.ClientCertificateKeyData) || + !string.IsNullOrWhiteSpace(this.ClientKeyFilePath))) { var cert = CertUtils.GeneratePfx(this); #if NET452 - ((WebRequestHandler) handler).ClientCertificates.Add(cert); + ((WebRequestHandler)handler).ClientCertificates.Add(cert); #else handler.ClientCertificates.Add(cert); #endif diff --git a/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs b/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs index 8787ec11f..4d00fe7b9 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.InCluster.cs @@ -7,9 +7,11 @@ namespace k8s public partial class KubernetesClientConfiguration { private static string ServiceAccountPath = - Path.Combine(new string[] { - $"{Path.DirectorySeparatorChar}var", "run", "secrets", "kubernetes.io", "serviceaccount" + Path.Combine(new string[] + { + $"{Path.DirectorySeparatorChar}var", "run", "secrets", "kubernetes.io", "serviceaccount", }); + private const string ServiceAccountTokenKeyFileName = "token"; private const string ServiceAccountRootCAKeyFileName = "ca.crt"; @@ -21,11 +23,13 @@ public static Boolean IsInCluster() { return false; } + var tokenPath = Path.Combine(ServiceAccountPath, ServiceAccountTokenKeyFileName); if (!File.Exists(tokenPath)) { return false; } + var certPath = Path.Combine(ServiceAccountPath, ServiceAccountRootCAKeyFileName); return File.Exists(certPath); } @@ -47,7 +51,7 @@ public static KubernetesClientConfiguration InClusterConfig() { Host = new UriBuilder("https", host, Convert.ToInt32(port)).ToString(), AccessToken = token, - SslCaCerts = CertUtils.LoadPemFileCert(rootCAFile) + SslCaCerts = CertUtils.LoadPemFileCert(rootCAFile), }; } } diff --git a/src/KubernetesClient/KubernetesEntityAttribute.cs b/src/KubernetesClient/KubernetesEntityAttribute.cs index bea1a8de0..c3f1000ae 100644 --- a/src/KubernetesClient/KubernetesEntityAttribute.cs +++ b/src/KubernetesClient/KubernetesEntityAttribute.cs @@ -5,22 +5,25 @@ namespace k8s.Models /// /// Describes object type in Kubernetes /// - public class KubernetesEntityAttribute : Attribute + public sealed class KubernetesEntityAttribute : Attribute { /// - /// The Kubernetes named schema this object is based on + /// The Kubernetes named schema this object is based on. /// public string Kind { get; set; } + /// - /// The Group this Kubernetes type belongs to + /// The Group this Kubernetes type belongs to. /// public string Group { get; set; } + /// - /// The API Version this Kubernetes type belongs to + /// The API Version this Kubernetes type belongs to. /// public string ApiVersion { get; set; } + /// - /// The plural name of the entity + /// The plural name of the entity. /// public string PluralName { get; set; } } diff --git a/src/KubernetesClient/KubernetesException.cs b/src/KubernetesClient/KubernetesException.cs index ee25cda3e..a5635816c 100644 --- a/src/KubernetesClient/KubernetesException.cs +++ b/src/KubernetesClient/KubernetesException.cs @@ -76,10 +76,6 @@ protected KubernetesException(SerializationInfo info, StreamingContext context) /// Gets, when this exception was raised because of a Kubernetes status message, the underlying /// Kubernetes status message. /// - public V1Status Status - { - get; - private set; - } + public V1Status Status { get; private set; } } } diff --git a/src/KubernetesClient/KubernetesList.cs b/src/KubernetesClient/KubernetesList.cs index 5eb37c574..d13a8c7c0 100644 --- a/src/KubernetesClient/KubernetesList.cs +++ b/src/KubernetesClient/KubernetesList.cs @@ -6,11 +6,10 @@ namespace k8s.Models { - public class KubernetesList : IMetadata, IItems where T : IKubernetesObject { - - public KubernetesList(IList items, string apiVersion = default(string), string kind = default(string), V1ListMeta metadata = default(V1ListMeta)) + public KubernetesList(IList items, string apiVersion = default(string), string kind = default(string), + V1ListMeta metadata = default(V1ListMeta)) { ApiVersion = apiVersion; Items = items; @@ -29,8 +28,7 @@ public class KubernetesList : IMetadata, IItems where T : IKub [JsonProperty(PropertyName = "apiVersion")] public string ApiVersion { get; set; } - [JsonProperty(PropertyName = "items")] - public IList Items { get; set; } + [JsonProperty(PropertyName = "items")] public IList Items { get; set; } /// /// Gets or sets kind is a string value representing the REST resource @@ -60,6 +58,7 @@ public void Validate() { throw new ValidationException(ValidationRules.CannotBeNull, "Items"); } + if (Items != null) { foreach (var element in Items.OfType()) diff --git a/src/KubernetesClient/ModelExtensions.cs b/src/KubernetesClient/ModelExtensions.cs index c559ebaf1..020c69640 100644 --- a/src/KubernetesClient/ModelExtensions.cs +++ b/src/KubernetesClient/ModelExtensions.cs @@ -12,8 +12,9 @@ public override string ToString() { reason = ((HttpStatusCode)Code.Value).ToString(); } + return string.IsNullOrEmpty(Message) ? string.IsNullOrEmpty(reason) ? Status : reason : - string.IsNullOrEmpty(reason) ? Message : $"{reason} - {Message}"; + string.IsNullOrEmpty(reason) ? Message : $"{reason} - {Message}"; } } } diff --git a/src/KubernetesClient/Properties/AssemblyInfo.cs b/src/KubernetesClient/Properties/AssemblyInfo.cs index 651061524..2ee02145c 100644 --- a/src/KubernetesClient/Properties/AssemblyInfo.cs +++ b/src/KubernetesClient/Properties/AssemblyInfo.cs @@ -1,4 +1,8 @@ using System.Runtime.CompilerServices; -[assembly: InternalsVisibleTo("KubernetesClient.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004917ad4e106c573cc5dbb3b7456de8b6c07128ae43de292752b339eb423de60f0db6a6c0cb21e6640fc672cc84df4a772db85df1505e5dd08c98d5d115eed7a7b59c67fe1f4b32fa716b7177743a417b3fcf88606861650a81f565ac6614abbf8b6b7710436edb497a83974165f9fe6995b70af13047a110bf63cdbfa45f89ac")] -[assembly: InternalsVisibleTo("KubernetesClient.Informers.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004917ad4e106c573cc5dbb3b7456de8b6c07128ae43de292752b339eb423de60f0db6a6c0cb21e6640fc672cc84df4a772db85df1505e5dd08c98d5d115eed7a7b59c67fe1f4b32fa716b7177743a417b3fcf88606861650a81f565ac6614abbf8b6b7710436edb497a83974165f9fe6995b70af13047a110bf63cdbfa45f89ac")] +[assembly: + InternalsVisibleTo( + "KubernetesClient.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004917ad4e106c573cc5dbb3b7456de8b6c07128ae43de292752b339eb423de60f0db6a6c0cb21e6640fc672cc84df4a772db85df1505e5dd08c98d5d115eed7a7b59c67fe1f4b32fa716b7177743a417b3fcf88606861650a81f565ac6614abbf8b6b7710436edb497a83974165f9fe6995b70af13047a110bf63cdbfa45f89ac")] +[assembly: + InternalsVisibleTo( + "KubernetesClient.Informers.Tests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004917ad4e106c573cc5dbb3b7456de8b6c07128ae43de292752b339eb423de60f0db6a6c0cb21e6640fc672cc84df4a772db85df1505e5dd08c98d5d115eed7a7b59c67fe1f4b32fa716b7177743a417b3fcf88606861650a81f565ac6614abbf8b6b7710436edb497a83974165f9fe6995b70af13047a110bf63cdbfa45f89ac")] diff --git a/src/KubernetesClient/ResourceQuantity.cs b/src/KubernetesClient/ResourceQuantity.cs index 80214f702..b85734172 100644 --- a/src/KubernetesClient/ResourceQuantity.cs +++ b/src/KubernetesClient/ResourceQuantity.cs @@ -93,7 +93,7 @@ public enum SuffixFormat { DecimalExponent, BinarySI, - DecimalSI + DecimalSI, } public static readonly decimal MaxAllowed = (decimal)BigInteger.Pow(2, 63) - 1; @@ -130,14 +130,17 @@ public override bool Equals(object obj) { return false; } + if (ReferenceEquals(this, obj)) { return true; } + if (obj.GetType() != GetType()) { return false; } + return Equals((ResourceQuantity)obj); } @@ -258,28 +261,28 @@ private class Suffixer { // 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 DecSuffixes = new Dictionary { - {"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) @@ -394,6 +397,7 @@ private static Fraction Roundup(Fraction lastv) { lastv = round + 1; } + return lastv; } } diff --git a/src/KubernetesClient/StreamDemuxer.cs b/src/KubernetesClient/StreamDemuxer.cs index e0687f1ff..c8d859e56 100644 --- a/src/KubernetesClient/StreamDemuxer.cs +++ b/src/KubernetesClient/StreamDemuxer.cs @@ -43,7 +43,8 @@ public class StreamDemuxer : IStreamDemuxer /// A value indicating whether this instance of the owns the underlying , /// and should dispose of it when this instance is disposed of. /// - public StreamDemuxer(WebSocket webSocket, StreamType streamType = StreamType.RemoteCommand, bool ownsSocket = false) + public StreamDemuxer(WebSocket webSocket, StreamType streamType = StreamType.RemoteCommand, + bool ownsSocket = false) { this.streamType = streamType; this.webSocket = webSocket ?? throw new ArgumentNullException(nameof(webSocket)); @@ -148,7 +149,8 @@ public Stream GetStream(byte? inputIndex, byte? outputIndex) /// /// A which represents the asynchronous operation. /// - public Task Write(ChannelIndex index, byte[] buffer, int offset, int count, CancellationToken cancellationToken = default(CancellationToken)) + public Task Write(ChannelIndex index, byte[] buffer, int offset, int count, + CancellationToken cancellationToken = default(CancellationToken)) { return Write((byte)index, buffer, offset, count, cancellationToken); } @@ -174,7 +176,8 @@ public Stream GetStream(byte? inputIndex, byte? outputIndex) /// /// A which represents the asynchronous operation. /// - public async Task Write(byte index, byte[] buffer, int offset, int count, CancellationToken cancellationToken = default(CancellationToken)) + public async Task Write(byte index, byte[] buffer, int offset, int count, + CancellationToken cancellationToken = default(CancellationToken)) { byte[] writeBuffer = ArrayPool.Shared.Rent(count + 1); @@ -183,7 +186,8 @@ public Stream GetStream(byte? inputIndex, byte? outputIndex) writeBuffer[0] = (byte)index; Array.Copy(buffer, offset, writeBuffer, 1, count); ArraySegment segment = new ArraySegment(writeBuffer, 0, count + 1); - await this.webSocket.SendAsync(segment, WebSocketMessageType.Binary, false, cancellationToken).ConfigureAwait(false); + await this.webSocket.SendAsync(segment, WebSocketMessageType.Binary, false, cancellationToken) + .ConfigureAwait(false); } finally { @@ -246,6 +250,7 @@ protected async Task RunLoop(CancellationToken cancellationToken) this.buffers[streamIndex].Write(buffer, extraByteCount, bytesCount); } } + streamBytesToSkipMap[streamIndex] = bytesToSkip; if (result.EndOfMessage == true) @@ -257,7 +262,6 @@ protected async Task RunLoop(CancellationToken cancellationToken) result = await this.webSocket.ReceiveAsync(segment, cancellationToken).ConfigureAwait(false); } } - } finally { diff --git a/src/KubernetesClient/StreamType.cs b/src/KubernetesClient/StreamType.cs index c53d478ff..c138ff726 100644 --- a/src/KubernetesClient/StreamType.cs +++ b/src/KubernetesClient/StreamType.cs @@ -17,6 +17,6 @@ public enum StreamType /// /// This object is used in port forwarding. /// - PortForward + PortForward, } } diff --git a/src/KubernetesClient/Utilities.cs b/src/KubernetesClient/Utilities.cs index 1975ac381..1356a70fb 100644 --- a/src/KubernetesClient/Utilities.cs +++ b/src/KubernetesClient/Utilities.cs @@ -8,10 +8,21 @@ internal static class Utilities /// Given a that is building a query string, adds a parameter to it. public static void AddQueryParameter(StringBuilder sb, string key, string value) { - if (sb == null) throw new ArgumentNullException(nameof(sb)); - if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key)); + if (sb == null) + { + throw new ArgumentNullException(nameof(sb)); + } + + if (string.IsNullOrEmpty(key)) + { + throw new ArgumentNullException(nameof(key)); + } + sb.Append(sb.Length != 0 ? '&' : '?').Append(Uri.EscapeDataString(key)).Append('='); - if (!string.IsNullOrEmpty(value)) sb.Append(Uri.EscapeDataString(value)); + if (!string.IsNullOrEmpty(value)) + { + sb.Append(Uri.EscapeDataString(value)); + } } } } diff --git a/src/KubernetesClient/V1Patch.cs b/src/KubernetesClient/V1Patch.cs index 19ff4a93f..827e2079d 100644 --- a/src/KubernetesClient/V1Patch.cs +++ b/src/KubernetesClient/V1Patch.cs @@ -27,7 +27,6 @@ public override bool CanConvert(Type objectType) [JsonConverter(typeof(V1PathJsonConverter))] public partial class V1Patch { - public enum PathType { JsonPatch, diff --git a/src/KubernetesClient/V1Status.ObjectView.cs b/src/KubernetesClient/V1Status.ObjectView.cs index efcdc3903..474fbe767 100644 --- a/src/KubernetesClient/V1Status.ObjectView.cs +++ b/src/KubernetesClient/V1Status.ObjectView.cs @@ -27,11 +27,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist // should be an object } - return new V1Status - { - _original = obj, - HasObject = true - }; + return new V1Status { _original = obj, HasObject = true }; } public override bool CanConvert(Type objectType) diff --git a/src/KubernetesClient/Watcher.cs b/src/KubernetesClient/Watcher.cs index d2ce04350..78417f691 100644 --- a/src/KubernetesClient/Watcher.cs +++ b/src/KubernetesClient/Watcher.cs @@ -61,7 +61,8 @@ public class Watcher : IDisposable /// /// The action to invoke when the server closes the connection. /// - public Watcher(Func> streamReaderCreator, Action onEvent, Action onError, Action onClosed = null) + public Watcher(Func> streamReaderCreator, Action onEvent, + Action onError, Action onClosed = null) : this( async () => (TextReader)await streamReaderCreator().ConfigureAwait(false), onEvent, onError, onClosed) @@ -83,7 +84,8 @@ public Watcher(Func> streamReaderCreator, Action /// The action to invoke when the server closes the connection. /// - public Watcher(Func> streamReaderCreator, Action onEvent, Action onError, Action onClosed = null) + public Watcher(Func> streamReaderCreator, Action onEvent, + Action onError, Action onClosed = null) { _streamReaderCreator = streamReaderCreator; OnEvent += onEvent; @@ -141,7 +143,8 @@ private async Task WatcherLoop(CancellationToken cancellationToken) try { - var genericEvent = SafeJsonConvert.DeserializeObject.WatchEvent>(line); + var genericEvent = + SafeJsonConvert.DeserializeObject.WatchEvent>(line); if (genericEvent.Object.Kind == "Status") { diff --git a/src/KubernetesClient/WatcherDelegatingHandler.cs b/src/KubernetesClient/WatcherDelegatingHandler.cs index 21fc36945..f65ed3187 100644 --- a/src/KubernetesClient/WatcherDelegatingHandler.cs +++ b/src/KubernetesClient/WatcherDelegatingHandler.cs @@ -58,11 +58,13 @@ public override async Task FlushAsync(CancellationToken cancellationToken) public override int Read(byte[] buffer, int offset, int count) => _innerStream.ReadAsync(buffer, offset, count, _cancellationToken).GetAwaiter().GetResult(); - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public override async Task ReadAsync(byte[] buffer, int offset, int count, + CancellationToken cancellationToken) { using (var cancellationTokenSource = CreateCancellationTokenSource(cancellationToken)) { - return await _innerStream.ReadAsync(buffer, offset, count, cancellationTokenSource.Token).ConfigureAwait(false); + return await _innerStream.ReadAsync(buffer, offset, count, cancellationTokenSource.Token) + .ConfigureAwait(false); } } @@ -73,11 +75,13 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, public override void Write(byte[] buffer, int offset, int count) => _innerStream.WriteAsync(buffer, offset, count, _cancellationToken).GetAwaiter().GetResult(); - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + public override async Task WriteAsync(byte[] buffer, int offset, int count, + CancellationToken cancellationToken) { using (var cancellationTokenSource = CreateCancellationTokenSource(cancellationToken)) { - await _innerStream.WriteAsync(buffer, offset, count, cancellationTokenSource.Token).ConfigureAwait(false); + await _innerStream.WriteAsync(buffer, offset, count, cancellationTokenSource.Token) + .ConfigureAwait(false); } } @@ -101,6 +105,7 @@ protected override void Dispose(bool disposing) { _innerStream.Dispose(); } + base.Dispose(disposing); } @@ -205,11 +210,13 @@ public async Task PeekLineAsync() public override int Read(char[] buffer, int index, int count) => throw new NotImplementedException(); - public override Task ReadAsync(char[] buffer, int index, int count) => throw new NotImplementedException(); + public override Task ReadAsync(char[] buffer, int index, int count) => + throw new NotImplementedException(); public override int ReadBlock(char[] buffer, int index, int count) => throw new NotImplementedException(); - public override Task ReadBlockAsync(char[] buffer, int index, int count) => throw new NotImplementedException(); + public override Task ReadBlockAsync(char[] buffer, int index, int count) => + throw new NotImplementedException(); public override string ReadToEnd() => throw new NotImplementedException(); @@ -221,6 +228,7 @@ protected override void Dispose(bool disposing) { _inner.Dispose(); } + base.Dispose(disposing); } } diff --git a/src/KubernetesClient/WebSocketBuilder.cs b/src/KubernetesClient/WebSocketBuilder.cs index ec33eba27..68b9844f9 100644 --- a/src/KubernetesClient/WebSocketBuilder.cs +++ b/src/KubernetesClient/WebSocketBuilder.cs @@ -40,7 +40,8 @@ public virtual WebSocketBuilder AddClientCertificate(X509Certificate2 certificat } #if (NET452 || NETSTANDARD2_0) - public WebSocketBuilder SetServerCertificateValidationCallback(RemoteCertificateValidationCallback validationCallback) + public WebSocketBuilder SetServerCertificateValidationCallback( + RemoteCertificateValidationCallback validationCallback) { System.Net.ServicePointManager.ServerCertificateValidationCallback += validationCallback; return this; @@ -55,7 +56,8 @@ public void CleanupServerCertificateValidationCallback(RemoteCertificateValidati #if NETCOREAPP2_1 public WebSocketBuilder ExpectServerCertificate(X509Certificate2Collection serverCertificate) { - Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + Options.RemoteCertificateValidationCallback + = (sender, certificate, chain, sslPolicyErrors) => { return Kubernetes.CertificateValidationCallBack(sender, serverCertificate, certificate, chain, sslPolicyErrors); }; @@ -65,7 +67,8 @@ public WebSocketBuilder ExpectServerCertificate(X509Certificate2Collection serve public WebSocketBuilder SkipServerCertificateValidation() { - Options.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; + Options.RemoteCertificateValidationCallback + = (sender, certificate, chain, sslPolicyErrors) => true; return this; } diff --git a/src/KubernetesClient/Yaml.cs b/src/KubernetesClient/Yaml.cs index bc6b75ca0..dc8397192 100644 --- a/src/KubernetesClient/Yaml.cs +++ b/src/KubernetesClient/Yaml.cs @@ -16,8 +16,7 @@ namespace k8s /// /// This is a utility class that helps you load objects from YAML files. /// - - public class Yaml + public static class Yaml { /// /// Load a collection of objects from a stream asynchronously @@ -44,7 +43,6 @@ public static async Task> LoadAllFromStreamAsync(Stream stream, Dic /// /// A map from / to Type. For example "v1/Pod" -> typeof(V1Pod) /// - public static Task> LoadAllFromFileAsync(String fileName, Dictionary typeMap) { var reader = File.OpenRead(fileName); @@ -60,7 +58,6 @@ public static Task> LoadAllFromFileAsync(String fileName, Dictionar /// /// A map from / to Type. For example "v1/Pod" -> typeof(V1Pod) /// - public static List LoadAllFromString(String content, Dictionary typeMap) { var deserializer = @@ -95,6 +92,7 @@ public static List LoadAllFromString(String content, Dictionary(string content) { var deserializer = new DeserializerBuilder() - .WithNamingConvention(new CamelCaseNamingConvention()) - .WithTypeInspector(ti => new AutoRestTypeInspector(ti)) - .WithTypeConverter(new IntOrStringYamlConverter()) - .Build(); + .WithNamingConvention(new CamelCaseNamingConvention()) + .WithTypeInspector(ti => new AutoRestTypeInspector(ti)) + .WithTypeConverter(new IntOrStringYamlConverter()) + .Build(); var obj = deserializer.Deserialize(content); return obj; } @@ -133,11 +131,11 @@ public static string SaveToString(T value) var serializer = new SerializerBuilder() - .DisableAliases() - .WithNamingConvention(new CamelCaseNamingConvention()) - .WithTypeInspector(ti => new AutoRestTypeInspector(ti)) - .WithTypeConverter(new IntOrStringYamlConverter()) - .BuildValueSerializer(); + .DisableAliases() + .WithNamingConvention(new CamelCaseNamingConvention()) + .WithTypeInspector(ti => new AutoRestTypeInspector(ti)) + .WithTypeConverter(new IntOrStringYamlConverter()) + .BuildValueSerializer(); emitter.Emit(new StreamStart()); emitter.Emit(new DocumentStart()); serializer.SerializeValue(emitter, value, typeof(T)); @@ -207,9 +205,23 @@ public RenamedPropertyDescriptor(IPropertyDescriptor inner, string name) public Type Type => _inner.Type; - public Type TypeOverride { get => _inner.TypeOverride; set => _inner.TypeOverride = value; } - public int Order { get => _inner.Order; set => _inner.Order = value; } - public ScalarStyle ScalarStyle { get => _inner.ScalarStyle; set => _inner.ScalarStyle = value; } + public Type TypeOverride + { + get => _inner.TypeOverride; + set => _inner.TypeOverride = value; + } + + public int Order + { + get => _inner.Order; + set => _inner.Order = value; + } + + public ScalarStyle ScalarStyle + { + get => _inner.ScalarStyle; + set => _inner.ScalarStyle = value; + } public T GetCustomAttribute() where T : Attribute { diff --git a/stylecop.json b/stylecop.json index 0d68ceb3c..c34e89b06 100644 --- a/stylecop.json +++ b/stylecop.json @@ -1,5 +1,10 @@ -{ - "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", - "settings": { - } +{ + "$schema": + "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "orderingRules": { + "systemUsingDirectivesFirst": false, + "usingDirectivesPlacement": "outsideNamespace" + } + } } diff --git a/tests/KubernetesClient.Tests/AuthTests.cs b/tests/KubernetesClient.Tests/AuthTests.cs index b6d2f5d77..b52dce2e5 100644 --- a/tests/KubernetesClient.Tests/AuthTests.cs +++ b/tests/KubernetesClient.Tests/AuthTests.cs @@ -42,10 +42,7 @@ public void Anonymous() { using (var server = new MockKubeApiServer(testOutput)) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = ExecuteListPods(client); @@ -59,10 +56,7 @@ public void Anonymous() return Task.FromResult(false); })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = ExecuteListPods(client); @@ -80,7 +74,8 @@ public void BasicAuth() { var header = cxt.Request.Headers["Authorization"].FirstOrDefault(); - var expect = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{testName}:{testPassword}"))) + var expect = new AuthenticationHeaderValue("Basic", + Convert.ToBase64String(Encoding.UTF8.GetBytes($"{testName}:{testPassword}"))) .ToString(); if (header != expect) @@ -97,7 +92,7 @@ public void BasicAuth() { Host = server.Uri.ToString(), Username = testName, - Password = testPassword + Password = testPassword, }); var listTask = ExecuteListPods(client); @@ -110,7 +105,7 @@ public void BasicAuth() { Host = server.Uri.ToString(), Username = "wrong name", - Password = testPassword + Password = testPassword, }); var listTask = ExecuteListPods(client); @@ -123,7 +118,7 @@ public void BasicAuth() { Host = server.Uri.ToString(), Username = testName, - Password = "wrong password" + Password = "wrong password", }); var listTask = ExecuteListPods(client); @@ -136,7 +131,7 @@ public void BasicAuth() { Host = server.Uri.ToString(), Username = "both wrong", - Password = "wrong password" + Password = "wrong password", }); var listTask = ExecuteListPods(client); @@ -145,10 +140,7 @@ public void BasicAuth() } { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = ExecuteListPods(client); @@ -159,7 +151,7 @@ public void BasicAuth() var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), - Username = "xx" + Username = "xx", }); var listTask = ExecuteListPods(client); @@ -188,7 +180,8 @@ public void Cert() if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - using (MemoryStream serverCertificateStream = new MemoryStream(Convert.FromBase64String(serverCertificateData))) + using (MemoryStream serverCertificateStream = + new MemoryStream(Convert.FromBase64String(serverCertificateData))) { serverCertificate = OpenCertificateStore(serverCertificateStream); } @@ -212,7 +205,7 @@ public void Cert() { clientCertificateValidationCalled = true; return clientCertificate.Equals(certificate); - } + }, }); })) { @@ -224,7 +217,7 @@ public void Cert() ClientCertificateData = clientCertificateData, ClientCertificateKeyData = clientCertificateKeyData, SslCaCerts = new X509Certificate2Collection(serverCertificate), - SkipTlsVerify = false + SkipTlsVerify = false, }); var listTask = ExecuteListPods(client); @@ -241,7 +234,7 @@ public void Cert() Host = server.Uri.ToString(), ClientCertificateData = clientCertificateData, ClientCertificateKeyData = clientCertificateKeyData, - SkipTlsVerify = true + SkipTlsVerify = true, }); var listTask = ExecuteListPods(client); @@ -256,9 +249,10 @@ public void Cert() var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), - ClientCertificateFilePath = "assets/client.crt", // TODO amazoning why client.crt != client-data.txt + ClientCertificateFilePath = + "assets/client.crt", // TODO amazoning why client.crt != client-data.txt ClientKeyFilePath = "assets/client.key", - SkipTlsVerify = true + SkipTlsVerify = true, }); Assert.ThrowsAny(() => ExecuteListPods(client)); @@ -270,7 +264,7 @@ public void Cert() var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), - SkipTlsVerify = true + SkipTlsVerify = true, }); Assert.ThrowsAny(() => ExecuteListPods(client)); @@ -285,18 +279,24 @@ public void Cert() [Fact] public void ExternalToken() { - const string token = "testingtoken"; - const string name = "testing_irrelevant"; + const string token + = "testingtoken"; + const string name + = "testing_irrelevant"; - using (var server = new MockKubeApiServer(testOutput, cxt => + using (var server + = new MockKubeApiServer(testOutput, cxt => { - var header = cxt.Request.Headers["Authorization"].FirstOrDefault(); + var header + = cxt.Request.Headers["Authorization"].FirstOrDefault(); - var expect = new AuthenticationHeaderValue("Bearer", token).ToString(); + var expect + = new AuthenticationHeaderValue("Bearer", token).ToString(); if (header != expect) { - cxt.Response.StatusCode = (int) HttpStatusCode.Unauthorized; + cxt.Response.StatusCode + = (int) HttpStatusCode.Unauthorized; return Task.FromResult(false); } @@ -304,18 +304,26 @@ public void ExternalToken() })) { { - var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), token, name); - var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name); - var client = new Kubernetes(clientConfig); - var listTask = ExecuteListPods(client); + var kubernetesConfig + = GetK8SConfiguration(server.Uri.ToString(), token, name); + var clientConfig + = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name); + var client + = new Kubernetes(clientConfig); + var listTask + = ExecuteListPods(client); Assert.True(listTask.Response.IsSuccessStatusCode); Assert.Equal(1, listTask.Body.Items.Count); } { - var kubernetesConfig = GetK8SConfiguration(server.Uri.ToString(), "wrong token", name); - var clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name); - var client = new Kubernetes(clientConfig); - var listTask = ExecuteListPods(client); + var kubernetesConfig + = GetK8SConfiguration(server.Uri.ToString(), "wrong token", name); + var clientConfig + = KubernetesClientConfiguration.BuildConfigFromConfigObject(kubernetesConfig, name); + var client + = new Kubernetes(clientConfig); + var listTask + = ExecuteListPods(client); Assert.Equal(HttpStatusCode.Unauthorized, listTask.Response.StatusCode); } } @@ -346,7 +354,7 @@ public void Token() var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), - AccessToken = token + AccessToken = token, }); var listTask = ExecuteListPods(client); @@ -358,7 +366,7 @@ public void Token() var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString(), - AccessToken = "wrong token" + AccessToken = "wrong token", }); var listTask = ExecuteListPods(client); @@ -372,7 +380,7 @@ public void Token() { Host = server.Uri.ToString(), Username = "wrong name", - Password = "same password" + Password = "same password", }); var listTask = ExecuteListPods(client); @@ -381,10 +389,7 @@ public void Token() } { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = ExecuteListPods(client); @@ -420,7 +425,7 @@ private K8SConfiguration GetK8SConfiguration(string serverUri, string token, str var contexts = new List { - new Context {Name = name, ContextDetails = new ContextDetails {Cluster = name, User = username}} + new Context {Name = name, ContextDetails = new ContextDetails {Cluster = name, User = username } }, }; var responseJson = $"{{\"apiVersion\": \"testingversion\", \"status\": {{\"token\": \"{token}\"}}}}"; @@ -431,19 +436,27 @@ private K8SConfiguration GetK8SConfiguration(string serverUri, string token, str new Cluster { Name = name, - ClusterEndpoint = new ClusterEndpoint {SkipTlsVerify = true, Server = serverUri} - } + ClusterEndpoint = new ClusterEndpoint {SkipTlsVerify = true, Server = serverUri } + }, }; var command = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "cmd.exe" : "echo"; if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { command = "printf"; + } var arguments = new string[] { }; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { arguments = ($"/c echo {responseJson}").Split(" "); - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { arguments = new[] { responseJson }; + } var users = new List @@ -460,7 +473,7 @@ private K8SConfiguration GetK8SConfiguration(string serverUri, string token, str Arguments = arguments.ToList() } } - } + }, }; var kubernetesConfig = new K8SConfiguration { Clusters = clusters, Users = users, Contexts = contexts }; return kubernetesConfig; diff --git a/tests/KubernetesClient.Tests/ByteBufferTests.cs b/tests/KubernetesClient.Tests/ByteBufferTests.cs index 2ba210f5d..f3f47a526 100644 --- a/tests/KubernetesClient.Tests/ByteBufferTests.cs +++ b/tests/KubernetesClient.Tests/ByteBufferTests.cs @@ -12,7 +12,10 @@ namespace k8s.Tests /// public class ByteBufferTests { - private readonly byte[] writeData = new byte[] { 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + private readonly byte[] writeData = new byte[] + { + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, + }; /// /// Tests a sequential read and write operation. @@ -261,8 +264,7 @@ public async Task ReadBlocksUntilDataAvailableTest() 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."); Assert.Equal(3, read); Assert.Equal(0xF0, readData[0]); @@ -427,26 +429,34 @@ public async Task ReadFirstTest() [Fact] public async Task RandomReadWriteTest() { - ByteBuffer buffer = new ByteBuffer(1, 1024 * 1024); + ByteBuffer buffer + = new ByteBuffer(1, 1024 * 1024); - var generatorTask = Task.Run(() => this.Generate(buffer, SHA256.Create())); - var consumerTask = Task.Run(() => this.Consume(buffer, SHA256.Create())); + var generatorTask + = Task.Run(() => this.Generate(buffer, SHA256.Create())); + var consumerTask + = Task.Run(() => this.Consume(buffer, SHA256.Create())); await Task.WhenAll(generatorTask, consumerTask); - var generatorHash = await generatorTask; - var consumerHash = await consumerTask; + var generatorHash + = await generatorTask; + var consumerHash + = await consumerTask; Assert.Equal(generatorHash, consumerHash); } private byte[] Generate(ByteBuffer buffer, HashAlgorithm hash) { - RandomNumberGenerator g = RandomNumberGenerator.Create(); + RandomNumberGenerator g + = RandomNumberGenerator.Create(); - byte[] next = new byte[32]; + byte[] next + = new byte[32]; - int iterations = 0; + int iterations + = 0; while (buffer.Size < buffer.MaximumSize) { iterations++; @@ -463,14 +473,19 @@ private byte[] Generate(ByteBuffer buffer, HashAlgorithm hash) private byte[] Consume(ByteBuffer buffer, HashAlgorithm hash) { - byte[] data = new byte[32]; + byte[] data + = new byte[32]; - AsyncAutoResetEvent onBufferResized = new AsyncAutoResetEvent(); - buffer.OnResize += (sender, e) => onBufferResized.Set(); + AsyncAutoResetEvent onBufferResized + = new AsyncAutoResetEvent(); + buffer.OnResize + += (sender, e) => onBufferResized.Set(); int read; - int iterations = 0; - while ((read = buffer.Read(data, 0, data.Length)) > 0) + int iterations + = 0; + while ((read + = buffer.Read(data, 0, data.Length)) > 0) { iterations++; diff --git a/tests/KubernetesClient.Tests/CertUtilsTests.cs b/tests/KubernetesClient.Tests/CertUtilsTests.cs index 10679cbd0..2eb471b5c 100644 --- a/tests/KubernetesClient.Tests/CertUtilsTests.cs +++ b/tests/KubernetesClient.Tests/CertUtilsTests.cs @@ -14,13 +14,13 @@ public class CertUtilsTests /// This file contains a sample kubeconfig file. The paths to the certificate files are relative /// to the current working directly. /// - private static readonly string kubeConfigFileName = "assets/kubeconfig.yml"; + private const string KubeConfigFileName = "assets/kubeconfig.yml"; /// /// This file contains a sample kubeconfig file. The paths to the certificate files are relative /// to the directory in which the kubeconfig file is located. /// - private static readonly string kubeConfigWithRelativePathsFileName = "assets/kubeconfig.relative.yml"; + private const string KubeConfigWithRelativePathsFileName = "assets/kubeconfig.relative.yml"; /// /// Checks that a certificate can be loaded from files. @@ -28,7 +28,8 @@ public class CertUtilsTests [Fact] public void LoadFromFiles() { - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(kubeConfigFileName, "federal-context", useRelativePaths: false); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(KubeConfigFileName, "federal-context", + useRelativePaths: false); // Just validate that this doesn't throw and private key is non-null var cert = CertUtils.GeneratePfx(cfg); @@ -41,7 +42,8 @@ public void LoadFromFiles() [Fact] public void LoadFromFilesRelativePath() { - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(kubeConfigWithRelativePathsFileName, "federal-context"); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(KubeConfigWithRelativePathsFileName, + "federal-context"); // Just validate that this doesn't throw and private key is non-null var cert = CertUtils.GeneratePfx(cfg); @@ -54,7 +56,8 @@ public void LoadFromFilesRelativePath() [Fact] public void LoadFromInlineData() { - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(kubeConfigFileName, "victorian-context", useRelativePaths: false); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(KubeConfigFileName, "victorian-context", + useRelativePaths: false); // Just validate that this doesn't throw and private key is non-null var cert = CertUtils.GeneratePfx(cfg); @@ -67,7 +70,8 @@ public void LoadFromInlineData() [Fact] public void LoadFromInlineDataRelativePath() { - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(kubeConfigWithRelativePathsFileName, "victorian-context"); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(KubeConfigWithRelativePathsFileName, + "victorian-context"); // Just validate that this doesn't throw and private key is non-null var cert = CertUtils.GeneratePfx(cfg); diff --git a/tests/KubernetesClient.Tests/Kubernetes.Exec.Tests.cs b/tests/KubernetesClient.Tests/Kubernetes.Exec.Tests.cs index a1539a7f5..dacff3b03 100644 --- a/tests/KubernetesClient.Tests/Kubernetes.Exec.Tests.cs +++ b/tests/KubernetesClient.Tests/Kubernetes.Exec.Tests.cs @@ -48,9 +48,9 @@ public async Task Exec_DefaultContainer_StdOut() if (!Debugger.IsAttached) { CancellationSource.CancelAfter( - TimeSpan.FromSeconds(5) - ); + TimeSpan.FromSeconds(5)); } + await Host.StartAsync(TestCancellation); using (Kubernetes client = CreateTestClient()) @@ -66,14 +66,17 @@ public async Task Exec_DefaultContainer_StdOut() stdin: false, stdout: true, webSocketSubProtol: WebSocketProtocol.ChannelWebSocketProtocol, - cancellationToken: TestCancellation - ); - Assert.Equal(WebSocketProtocol.ChannelWebSocketProtocol, clientSocket.SubProtocol); // For WebSockets, the Kubernetes API defaults to the binary channel (v1) protocol. + cancellationToken: TestCancellation); + Assert.Equal(WebSocketProtocol.ChannelWebSocketProtocol, + clientSocket + .SubProtocol); // For WebSockets, the Kubernetes API defaults to the binary channel (v1) protocol. - testOutput.WriteLine($"Client socket connected (socket state is {clientSocket.State}). Waiting for server-side socket to become available..."); + testOutput.WriteLine( + $"Client socket connected (socket state is {clientSocket.State}). Waiting for server-side socket to become available..."); WebSocket serverSocket = await WebSocketTestAdapter.AcceptedPodExecV1Connection; - testOutput.WriteLine($"Server-side socket is now available (socket state is {serverSocket.State}). Sending data to server socket..."); + testOutput.WriteLine( + $"Server-side socket is now available (socket state is {serverSocket.State}). Sending data to server socket..."); const int STDOUT = 1; const string expectedOutput = "This is text send to STDOUT."; @@ -82,15 +85,15 @@ public async Task Exec_DefaultContainer_StdOut() testOutput.WriteLine($"Sent {bytesSent} bytes to server socket; receiving from client socket..."); (string receivedText, byte streamIndex, int bytesReceived) = await ReceiveTextMultiplexed(clientSocket); - testOutput.WriteLine($"Received {bytesReceived} bytes from client socket ('{receivedText}', stream {streamIndex})."); + testOutput.WriteLine( + $"Received {bytesReceived} bytes from client socket ('{receivedText}', stream {streamIndex})."); Assert.Equal(STDOUT, streamIndex); Assert.Equal(expectedOutput, receivedText); await Disconnect(clientSocket, serverSocket, closeStatus: WebSocketCloseStatus.NormalClosure, - closeStatusDescription: "Normal Closure" - ); + closeStatusDescription: "Normal Closure"); WebSocketTestAdapter.CompleteTest(); } @@ -100,11 +103,7 @@ await Disconnect(clientSocket, serverSocket, [Fact] public void GetExitCodeOrThrow_Success() { - var status = new V1Status() - { - Metadata = null, - Status = "Success", - }; + var status = new V1Status() { Metadata = null, Status = "Success", }; Assert.Equal(0, Kubernetes.GetExitCodeOrThrow(status)); } @@ -121,14 +120,10 @@ public void GetExitCodeOrThrow_NonZeroExitCode() Details = new V1StatusDetails() { Causes = new List() - { - new V1StatusCause() - { - Reason = "ExitCode", - Message = "1" - } - } - } + { + new V1StatusCause() {Reason = "ExitCode", Message = "1" } + } + }, }; Assert.Equal(1, Kubernetes.GetExitCodeOrThrow(status)); @@ -147,13 +142,9 @@ public void GetExitCodeOrThrow_InvalidExitCode() { Causes = new List() { - new V1StatusCause() - { - Reason = "ExitCode", - Message = "abc" - } + new V1StatusCause() {Reason = "ExitCode", Message = "abc" } } - } + }, }; var ex = Assert.Throws(() => Kubernetes.GetExitCodeOrThrow(status)); @@ -169,12 +160,7 @@ public void GetExitCodeOrThrow_NoExitCode() Status = "Failure", Message = "command terminated with non-zero exit code: Error executing in Docker Container: 1", Reason = "NonZeroExitCode", - Details = new V1StatusDetails() - { - Causes = new List() - { - } - } + Details = new V1StatusDetails() { Causes = new List() { } }, }; var ex = Assert.Throws(() => Kubernetes.GetExitCodeOrThrow(status)); @@ -184,12 +170,7 @@ public void GetExitCodeOrThrow_NoExitCode() [Fact] public void GetExitCodeOrThrow_OtherError() { - var status = new V1Status() - { - Metadata = null, - Status = "Failure", - Reason = "SomethingElse" - }; + var status = new V1Status() { Metadata = null, Status = "Failure", Reason = "SomethingElse" }; var ex = Assert.Throws(() => Kubernetes.GetExitCodeOrThrow(status)); Assert.Equal(status, ex.Status); @@ -213,12 +194,16 @@ public async Task NamespacedPodExecAsync_ActionNull() new object[] { Moq.Mock.Of(), new DelegatingHandler[] { } }); var command = new string[] { "/bin/bash", "-c", "echo Hello, World!" }; - kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) + kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, + "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, + CancellationToken.None)) .Returns(Task.FromResult(muxedStream.Object)); using (Kubernetes client = kubernetesMock.Object) { - await Assert.ThrowsAsync(() => client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", command, false, null, CancellationToken.None)).ConfigureAwait(false); + await Assert.ThrowsAsync(() => client.NamespacedPodExecAsync("pod-name", + "pod-namespace", "my-container", command, false, null, CancellationToken.None)) + .ConfigureAwait(false); } } } @@ -232,12 +217,16 @@ public async Task NamespacedPodExecAsync_HttpException_WithStatus() var handler = new ExecAsyncCallback((stdIn, stdOut, stdError) => Task.CompletedTask); var status = new V1Status(); - kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) + kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, + "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, + CancellationToken.None)) .Throws(new HttpOperationException() { Body = status }); using (Kubernetes client = kubernetesMock.Object) { - var ex = await Assert.ThrowsAsync(() => client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", command, false, handler, CancellationToken.None)).ConfigureAwait(false); + var ex = await Assert.ThrowsAsync(() => client.NamespacedPodExecAsync("pod-name", + "pod-namespace", "my-container", command, false, handler, CancellationToken.None)) + .ConfigureAwait(false); Assert.Same(status, ex.Status); } } @@ -251,12 +240,16 @@ public async Task NamespacedPodExecAsync_HttpException_NoStatus() var handler = new ExecAsyncCallback((stdIn, stdOut, stdError) => Task.CompletedTask); var exception = new HttpOperationException(); - kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) + kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, + "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, + CancellationToken.None)) .Throws(exception); using (Kubernetes client = kubernetesMock.Object) { - var ex = await Assert.ThrowsAsync(() => client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", command, false, handler, CancellationToken.None)).ConfigureAwait(false); + var ex = await Assert.ThrowsAsync(() => + client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", command, false, handler, + CancellationToken.None)).ConfigureAwait(false); Assert.Same(exception, ex); } } @@ -270,12 +263,16 @@ public async Task NamespacedPodExecAsync_GenericException() var handler = new ExecAsyncCallback((stdIn, stdOut, stdError) => Task.CompletedTask); var exception = new Exception(); - kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) + kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, + "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, + CancellationToken.None)) .Throws(exception); using (Kubernetes client = kubernetesMock.Object) { - var ex = await Assert.ThrowsAsync(() => client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", command, false, handler, CancellationToken.None)).ConfigureAwait(false); + var ex = await Assert.ThrowsAsync(() => client.NamespacedPodExecAsync("pod-name", + "pod-namespace", "my-container", command, false, handler, CancellationToken.None)) + .ConfigureAwait(false); Assert.Same(exception, ex); } } @@ -292,14 +289,10 @@ public async Task NamespacedPodExecAsync_ExitCode_NonZero() Details = new V1StatusDetails() { Causes = new List() - { - new V1StatusCause() - { - Reason = "ExitCode", - Message = "1" - } - } - } + { + new V1StatusCause() {Reason = "ExitCode", Message = "1" } + } + }, }; var processStatusJson = Encoding.UTF8.GetBytes(SafeJsonConvert.SerializeObject(processStatus)); @@ -321,12 +314,15 @@ public async Task NamespacedPodExecAsync_ExitCode_NonZero() var command = new string[] { "/bin/bash", "-c", "echo Hello, World!" }; var exception = new Exception(); - kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, CancellationToken.None)) + kubernetesMock.Setup(m => m.MuxedStreamNamespacedPodExecAsync("pod-name", "pod-namespace", command, + "my-container", true, true, true, false, WebSocketProtocol.V4BinaryWebsocketProtocol, null, + CancellationToken.None)) .Returns(Task.FromResult(muxedStream.Object)); using (Kubernetes client = kubernetesMock.Object) { - var exitCode = await client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", command, false, handler, CancellationToken.None).ConfigureAwait(false); + var exitCode = await client.NamespacedPodExecAsync("pod-name", "pod-namespace", "my-container", + command, false, handler, CancellationToken.None).ConfigureAwait(false); Assert.Equal(1, exitCode); } } diff --git a/tests/KubernetesClient.Tests/Kubernetes.WebSockets.Tests.cs b/tests/KubernetesClient.Tests/Kubernetes.WebSockets.Tests.cs index 1c4bb8de0..71cb886fd 100644 --- a/tests/KubernetesClient.Tests/Kubernetes.WebSockets.Tests.cs +++ b/tests/KubernetesClient.Tests/Kubernetes.WebSockets.Tests.cs @@ -27,7 +27,7 @@ public async Task WebSocketNamespacedPodExecAsync() var credentials = new BasicAuthenticationCredentials() { UserName = "my-user", - Password = "my-secret-password" + Password = "my-secret-password", }; Kubernetes client = new Kubernetes(credentials); @@ -47,18 +47,22 @@ public async Task WebSocketNamespacedPodExecAsync() tty: true, customHeaders: new Dictionary>() { - { "X-My-Header", new List() { "myHeaderValue", "myHeaderValue2"} } + {"X-My-Header", new List() {"myHeaderValue", "myHeaderValue2" } }, }, cancellationToken: CancellationToken.None).ConfigureAwait(false); var expectedHeaders = new Dictionary() { - { "X-My-Header", "myHeaderValue myHeaderValue2" }, - { "Authorization", "Basic bXktdXNlcjpteS1zZWNyZXQtcGFzc3dvcmQ=" } + {"X-My-Header", "myHeaderValue myHeaderValue2" }, + {"Authorization", "Basic bXktdXNlcjpteS1zZWNyZXQtcGFzc3dvcmQ=" }, }; - Assert.Equal(mockWebSocketBuilder.PublicWebSocket, webSocket); // Did the method return the correct web socket? - Assert.Equal(new Uri("ws://localhost/api/v1/namespaces/mynamespace/pods/mypod/exec?command=%2Fbin%2Fbash&command=-c&command=echo%20Hello%2C%20World%0Aexit%200%0A&container=mycontainer&stderr=1&stdin=1&stdout=1&tty=1"), mockWebSocketBuilder.Uri); // Did we connect to the correct URL? + Assert.Equal(mockWebSocketBuilder.PublicWebSocket, + webSocket); // Did the method return the correct web socket? + Assert.Equal( + new Uri( + "ws://localhost/api/v1/namespaces/mynamespace/pods/mypod/exec?command=%2Fbin%2Fbash&command=-c&command=echo%20Hello%2C%20World%0Aexit%200%0A&container=mycontainer&stderr=1&stdin=1&stdout=1&tty=1"), + mockWebSocketBuilder.Uri); // Did we connect to the correct URL? Assert.Empty(mockWebSocketBuilder.Certificates); // No certificates were used in this test Assert.Equal(expectedHeaders, mockWebSocketBuilder.RequestHeaders); // Did we use the expected headers } @@ -69,7 +73,7 @@ public async Task WebSocketNamespacedPodPortForwardAsync() var credentials = new BasicAuthenticationCredentials() { UserName = "my-user", - Password = "my-secret-password" + Password = "my-secret-password", }; Kubernetes client = new Kubernetes(credentials); @@ -84,18 +88,21 @@ public async Task WebSocketNamespacedPodPortForwardAsync() ports: new int[] { 80, 8080 }, customHeaders: new Dictionary>() { - { "X-My-Header", new List() { "myHeaderValue", "myHeaderValue2"} } + {"X-My-Header", new List() {"myHeaderValue", "myHeaderValue2" } }, }, cancellationToken: CancellationToken.None).ConfigureAwait(false); var expectedHeaders = new Dictionary() { - { "X-My-Header", "myHeaderValue myHeaderValue2" }, - { "Authorization", "Basic bXktdXNlcjpteS1zZWNyZXQtcGFzc3dvcmQ=" } + {"X-My-Header", "myHeaderValue myHeaderValue2" }, + {"Authorization", "Basic bXktdXNlcjpteS1zZWNyZXQtcGFzc3dvcmQ=" }, }; - Assert.Equal(mockWebSocketBuilder.PublicWebSocket, webSocket); // Did the method return the correct web socket? - Assert.Equal(new Uri("ws://localhost/api/v1/namespaces/mynamespace/pods/mypod/portforward?ports=80&ports=8080"), mockWebSocketBuilder.Uri); // Did we connect to the correct URL? + Assert.Equal(mockWebSocketBuilder.PublicWebSocket, + webSocket); // Did the method return the correct web socket? + Assert.Equal( + new Uri("ws://localhost/api/v1/namespaces/mynamespace/pods/mypod/portforward?ports=80&ports=8080"), + mockWebSocketBuilder.Uri); // Did we connect to the correct URL? Assert.Empty(mockWebSocketBuilder.Certificates); // No certificates were used in this test Assert.Equal(expectedHeaders, mockWebSocketBuilder.RequestHeaders); // Did we use the expected headers } @@ -106,7 +113,7 @@ public async Task WebSocketNamespacedPodAttachAsync() var credentials = new BasicAuthenticationCredentials() { UserName = "my-user", - Password = "my-secret-password" + Password = "my-secret-password", }; Kubernetes client = new Kubernetes(credentials); @@ -125,18 +132,22 @@ public async Task WebSocketNamespacedPodAttachAsync() tty: true, customHeaders: new Dictionary>() { - { "X-My-Header", new List() { "myHeaderValue", "myHeaderValue2"} } + {"X-My-Header", new List() {"myHeaderValue", "myHeaderValue2" } }, }, cancellationToken: CancellationToken.None).ConfigureAwait(false); var expectedHeaders = new Dictionary() { - { "X-My-Header", "myHeaderValue myHeaderValue2" }, - { "Authorization", "Basic bXktdXNlcjpteS1zZWNyZXQtcGFzc3dvcmQ=" } + {"X-My-Header", "myHeaderValue myHeaderValue2" }, + {"Authorization", "Basic bXktdXNlcjpteS1zZWNyZXQtcGFzc3dvcmQ=" }, }; - Assert.Equal(mockWebSocketBuilder.PublicWebSocket, webSocket); // Did the method return the correct web socket? - Assert.Equal(new Uri("ws://localhost:80/api/v1/namespaces/mynamespace/pods/mypod/attach?stderr=1&stdin=1&stdout=1&tty=1&container=my-container"), mockWebSocketBuilder.Uri); // Did we connect to the correct URL? + Assert.Equal(mockWebSocketBuilder.PublicWebSocket, + webSocket); // Did the method return the correct web socket? + Assert.Equal( + new Uri( + "ws://localhost:80/api/v1/namespaces/mynamespace/pods/mypod/attach?stderr=1&stdin=1&stdout=1&tty=1&container=my-container"), + mockWebSocketBuilder.Uri); // Did we connect to the correct URL? Assert.Empty(mockWebSocketBuilder.Certificates); // No certificates were used in this test Assert.Equal(expectedHeaders, mockWebSocketBuilder.RequestHeaders); // Did we use the expected headers } diff --git a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs index a5f23d8f2..80416f5bb 100755 --- a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs +++ b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs @@ -160,7 +160,9 @@ public void ContextNotFound() [Fact] public void CreatedFromPreLoadedConfig() { - var k8sConfig = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo("assets/kubeconfig.yml"), useRelativePaths: false); + var k8sConfig = + KubernetesClientConfiguration.LoadKubeConfig(new FileInfo("assets/kubeconfig.yml"), + useRelativePaths: false); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigObject(k8sConfig); Assert.NotNull(cfg.Host); } @@ -171,7 +173,8 @@ public void CreatedFromPreLoadedConfig() [Fact] public void DefaultConfigurationLoaded() { - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(new FileInfo("assets/kubeconfig.yml"), useRelativePaths: false); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(new FileInfo("assets/kubeconfig.yml"), + useRelativePaths: false); Assert.NotNull(cfg.Host); } @@ -182,7 +185,8 @@ public void DefaultConfigurationLoaded() public void IncompleteUserCredentials() { var fi = new FileInfo("assets/kubeconfig.no-credentials.yml"); - Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false)); + Assert.Throws(() => + KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false)); } /// @@ -245,7 +249,8 @@ public void UserPasswordAuthentication() public void UserNotFound() { var fi = new FileInfo("assets/kubeconfig.user-not-found.yml"); - Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false)); + Assert.Throws(() => + KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false)); } /// @@ -267,7 +272,8 @@ public void EmptyUserNotFound() public void OverrideByMasterUrl() { var fi = new FileInfo("assets/kubeconfig.yml"); - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, masterUrl: "http://test.server", useRelativePaths: false); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, masterUrl: "http://test.server", + useRelativePaths: false); Assert.Equal("http://test.server", cfg.Host); } @@ -332,7 +338,8 @@ public void DeletedConfigurationFile() public void DefaultConfigurationAsStringLoaded() { var filePath = "assets/kubeconfig.yml"; - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, useRelativePaths: false); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, + useRelativePaths: false); Assert.NotNull(cfg.Host); } @@ -358,7 +365,8 @@ public void AsUserExtra() { var filePath = "assets/kubeconfig.as-user-extra.yml"; - var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, useRelativePaths: false); + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, + useRelativePaths: false); Assert.NotNull(cfg.Host); } @@ -434,7 +442,8 @@ public void LoadKubeConfigFromEnvironmentVariable_MultipleConfigs() var filePath = Path.GetFullPath("assets/kubeconfig.relative.yml"); var environmentVariable = "KUBECONFIG_LoadKubeConfigFromEnvironmentVariable_MultipleConfigs"; - Environment.SetEnvironmentVariable(environmentVariable, string.Concat(filePath, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ';' : ':', filePath)); + Environment.SetEnvironmentVariable(environmentVariable, + string.Concat(filePath, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ';' : ':', filePath)); KubernetesClientConfiguration.KubeConfigEnvironmentVariable = environmentVariable; var cfg = KubernetesClientConfiguration.BuildDefaultConfig(); @@ -461,7 +470,10 @@ public void MergeKubeConfigNoDuplicates() var firstPath = Path.GetFullPath("assets/kubeconfig.as-user-extra.yml"); var secondPath = Path.GetFullPath("assets/kubeconfig.yml"); - var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(firstPath), new FileInfo(secondPath) }); + var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] + { + new FileInfo(firstPath), new FileInfo(secondPath), + }); // Merged file has 6 users now. Assert.Equal(6, cfg.Users.Count()); @@ -475,7 +487,10 @@ public void AlwaysPicksFirstOccurence() var firstPath = Path.GetFullPath("assets/kubeconfig.no-cluster.yml"); var secondPath = Path.GetFullPath("assets/kubeconfig.no-context.yml"); - var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(firstPath), new FileInfo(secondPath) }); + var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] + { + new FileInfo(firstPath), new FileInfo(secondPath), + }); var user = cfg.Users.Where(u => u.Name == "green-user").Single(); Assert.NotNull(user.UserCredentials.Password); @@ -488,7 +503,10 @@ public void ContextFromSecondWorks() var firstPath = Path.GetFullPath("assets/kubeconfig.no-current-context.yml"); var secondPath = Path.GetFullPath("assets/kubeconfig.no-user.yml"); - var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(firstPath), new FileInfo(secondPath) }); + var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] + { + new FileInfo(firstPath), new FileInfo(secondPath), + }); // green-user Assert.NotNull(cfg.CurrentContext); @@ -499,7 +517,10 @@ public void ContextPreferencesExtensionsMergeWithDuplicates() { var path = Path.GetFullPath("assets/kubeconfig.preferences-extensions.yml"); - var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(path), new FileInfo(path) }); + var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] + { + new FileInfo(path), new FileInfo(path), + }); Assert.Equal(1, cfg.Extensions.Count); Assert.Equal(1, cfg.Preferences.Count); @@ -555,7 +576,8 @@ private void AssertClusterEqual(Cluster expected, Cluster actual) { Assert.Equal(expected.Name, actual.Name); Assert.Equal(expected.ClusterEndpoint.CertificateAuthority, actual.ClusterEndpoint.CertificateAuthority); - Assert.Equal(expected.ClusterEndpoint.CertificateAuthorityData, actual.ClusterEndpoint.CertificateAuthorityData); + Assert.Equal(expected.ClusterEndpoint.CertificateAuthorityData, + actual.ClusterEndpoint.CertificateAuthorityData); Assert.Equal(expected.ClusterEndpoint.Server, actual.ClusterEndpoint.Server); Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify); } diff --git a/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs b/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs index 5d4ac9db0..220d209a6 100644 --- a/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs +++ b/tests/KubernetesClient.Tests/Logging/TestOutputLogger.cs @@ -26,10 +26,16 @@ sealed class TestOutputLogger public TestOutputLogger(ITestOutputHelper testOutput, string loggerCategory, LogLevel minLogLevel) { if (testOutput == null) + { throw new ArgumentNullException(nameof(testOutput)); + } if (String.IsNullOrWhiteSpace(loggerCategory)) - throw new ArgumentException("Argument cannot be null, empty, or entirely composed of whitespace: 'loggerCategory'.", nameof(loggerCategory)); + { + throw new ArgumentException( + "Argument cannot be null, empty, or entirely composed of whitespace: 'loggerCategory'.", + nameof(loggerCategory)); + } TestOutput = testOutput; LoggerCategory = loggerCategory; @@ -69,22 +75,23 @@ public TestOutputLogger(ITestOutputHelper testOutput, string loggerCategory, Log /// /// A function that creates a string log message from the and . /// - public void Log(LogLevel level, EventId eventId, TState state, Exception exception, Func formatter) + public void Log(LogLevel level, EventId eventId, TState state, Exception exception, + Func formatter) { if (formatter == null) + { throw new ArgumentNullException(nameof(formatter)); + } TestOutput.WriteLine(String.Format("[{0}] {1}: {2}", level, LoggerCategory, - formatter(state, exception) - )); + formatter(state, exception))); if (exception != null) { TestOutput.WriteLine( - exception.ToString() - ); + exception.ToString()); } } diff --git a/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs b/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs index 08ae7949f..4fad342fc 100644 --- a/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs +++ b/tests/KubernetesClient.Tests/Logging/TestOutputLoggerProvider.cs @@ -22,7 +22,9 @@ sealed class TestOutputLoggerProvider public TestOutputLoggerProvider(ITestOutputHelper testOutput, LogLevel minLogLevel) { if (testOutput == null) + { throw new ArgumentNullException(nameof(testOutput)); + } TestOutput = testOutput; MinLogLevel = minLogLevel; diff --git a/tests/KubernetesClient.Tests/Logging/TestOutputLoggingExtensions.cs b/tests/KubernetesClient.Tests/Logging/TestOutputLoggingExtensions.cs index c6d3532ce..4f94343c9 100644 --- a/tests/KubernetesClient.Tests/Logging/TestOutputLoggingExtensions.cs +++ b/tests/KubernetesClient.Tests/Logging/TestOutputLoggingExtensions.cs @@ -21,17 +21,21 @@ public static class TestOutputLoggingExtensions /// /// The minimum level to log at. /// - public static void AddTestOutput(this ILoggingBuilder logging, ITestOutputHelper testOutput, LogLevel minLogLevel = LogLevel.Information) + public static void AddTestOutput(this ILoggingBuilder logging, ITestOutputHelper testOutput, + LogLevel minLogLevel = LogLevel.Information) { if (logging == null) + { throw new ArgumentNullException(nameof(logging)); + } if (testOutput == null) + { throw new ArgumentNullException(nameof(testOutput)); + } logging.AddProvider( - new TestOutputLoggerProvider(testOutput, minLogLevel) - ); + new TestOutputLoggerProvider(testOutput, minLogLevel)); } /// @@ -49,17 +53,21 @@ public static void AddTestOutput(this ILoggingBuilder logging, ITestOutputHelper /// /// The logger factory (enables inline use / method-chaining). /// - public static ILoggerFactory AddTestOutput(this ILoggerFactory loggers, ITestOutputHelper testOutput, LogLevel minLogLevel = LogLevel.Information) + public static ILoggerFactory AddTestOutput(this ILoggerFactory loggers, ITestOutputHelper testOutput, + LogLevel minLogLevel = LogLevel.Information) { if (loggers == null) + { throw new ArgumentNullException(nameof(loggers)); + } if (testOutput == null) + { throw new ArgumentNullException(nameof(testOutput)); + } loggers.AddProvider( - new TestOutputLoggerProvider(testOutput, minLogLevel) - ); + new TestOutputLoggerProvider(testOutput, minLogLevel)); return loggers; } diff --git a/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs b/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs index 4869c4c86..02f8e9c5b 100644 --- a/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs +++ b/tests/KubernetesClient.Tests/Mock/MockKubeApiServer.cs @@ -18,12 +18,12 @@ public sealed class MockKubeApiServer : IDisposable { // paste from minikube /api/v1/namespaces/default/pods public const string MockPodResponse = - "{\r\n \"kind\": \"PodList\",\r\n \"apiVersion\": \"v1\",\r\n \"metadata\": {\r\n \"selfLink\": \"/api/v1/namespaces/default/pods\",\r\n \"resourceVersion\": \"1762810\"\r\n },\r\n \"items\": [\r\n {\r\n \"metadata\": {\r\n \"name\": \"nginx-1493591563-xb2v4\",\r\n \"generateName\": \"nginx-1493591563-\",\r\n \"namespace\": \"default\",\r\n \"selfLink\": \"/api/v1/namespaces/default/pods/nginx-1493591563-xb2v4\",\r\n \"uid\": \"ac1abb94-9c58-11e7-aaf5-00155d744505\",\r\n \"resourceVersion\": \"1737928\",\r\n \"creationTimestamp\": \"2017-09-18T10:03:51Z\",\r\n \"labels\": {\r\n \"app\": \"nginx\",\r\n \"pod-template-hash\": \"1493591563\"\r\n },\r\n \"annotations\": {\r\n \"kubernetes.io/created-by\": \"{\\\"kind\\\":\\\"SerializedReference\\\",\\\"apiVersion\\\":\\\"v1\\\",\\\"reference\\\":{\\\"kind\\\":\\\"ReplicaSet\\\",\\\"namespace\\\":\\\"default\\\",\\\"name\\\":\\\"nginx-1493591563\\\",\\\"uid\\\":\\\"ac013b63-9c58-11e7-aaf5-00155d744505\\\",\\\"apiVersion\\\":\\\"extensions\\\",\\\"resourceVersion\\\":\\\"5306\\\"}}\\n\"\r\n },\r\n \"ownerReferences\": [\r\n {\r\n \"apiVersion\": \"extensions/v1beta1\",\r\n \"kind\": \"ReplicaSet\",\r\n \"name\": \"nginx-1493591563\",\r\n \"uid\": \"ac013b63-9c58-11e7-aaf5-00155d744505\",\r\n \"controller\": true,\r\n \"blockOwnerDeletion\": true\r\n }\r\n ]\r\n },\r\n \"spec\": {\r\n \"volumes\": [\r\n {\r\n \"name\": \"default-token-3zzcj\",\r\n \"secret\": {\r\n \"secretName\": \"default-token-3zzcj\",\r\n \"defaultMode\": 420\r\n }\r\n }\r\n ],\r\n \"containers\": [\r\n {\r\n \"name\": \"nginx\",\r\n \"image\": \"nginx\",\r\n \"resources\": {},\r\n \"volumeMounts\": [\r\n {\r\n \"name\": \"default-token-3zzcj\",\r\n \"readOnly\": true,\r\n \"mountPath\": \"/var/run/secrets/kubernetes.io/serviceaccount\"\r\n }\r\n ],\r\n \"terminationMessagePath\": \"/dev/termination-log\",\r\n \"terminationMessagePolicy\": \"File\",\r\n \"imagePullPolicy\": \"Always\"\r\n }\r\n ],\r\n \"restartPolicy\": \"Always\",\r\n \"terminationGracePeriodSeconds\": 30,\r\n \"dnsPolicy\": \"ClusterFirst\",\r\n \"serviceAccountName\": \"default\",\r\n \"serviceAccount\": \"default\",\r\n \"nodeName\": \"ubuntu\",\r\n \"securityContext\": {},\r\n \"schedulerName\": \"default-scheduler\"\r\n },\r\n \"status\": {\r\n \"phase\": \"Running\",\r\n \"conditions\": [\r\n {\r\n \"type\": \"Initialized\",\r\n \"status\": \"True\",\r\n \"lastProbeTime\": null,\r\n \"lastTransitionTime\": \"2017-09-18T10:03:51Z\"\r\n },\r\n {\r\n \"type\": \"Ready\",\r\n \"status\": \"True\",\r\n \"lastProbeTime\": null,\r\n \"lastTransitionTime\": \"2017-10-12T07:09:21Z\"\r\n },\r\n {\r\n \"type\": \"PodScheduled\",\r\n \"status\": \"True\",\r\n \"lastProbeTime\": null,\r\n \"lastTransitionTime\": \"2017-09-18T10:03:51Z\"\r\n }\r\n ],\r\n \"hostIP\": \"192.168.188.42\",\r\n \"podIP\": \"172.17.0.5\",\r\n \"startTime\": \"2017-09-18T10:03:51Z\",\r\n \"containerStatuses\": [\r\n {\r\n \"name\": \"nginx\",\r\n \"state\": {\r\n \"running\": {\r\n \"startedAt\": \"2017-10-12T07:09:20Z\"\r\n }\r\n },\r\n \"lastState\": {\r\n \"terminated\": {\r\n \"exitCode\": 0,\r\n \"reason\": \"Completed\",\r\n \"startedAt\": \"2017-10-10T21:35:51Z\",\r\n \"finishedAt\": \"2017-10-12T07:07:37Z\",\r\n \"containerID\": \"docker://94df3f3965807421ad6dc76618e00b76cb15d024919c4946f3eb46a92659c62a\"\r\n }\r\n },\r\n \"ready\": true,\r\n \"restartCount\": 7,\r\n \"image\": \"nginx:latest\",\r\n \"imageID\": \"docker-pullable://nginx@sha256:004ac1d5e791e705f12a17c80d7bb1e8f7f01aa7dca7deee6e65a03465392072\",\r\n \"containerID\": \"docker://fa11bdd48c9b7d3a6c4c3f9b6d7319743c3455ab8d00c57d59c083b319b88194\"\r\n }\r\n ],\r\n \"qosClass\": \"BestEffort\"\r\n }\r\n }\r\n ]\r\n}" - ; + "{\r\n \"kind\": \"PodList\",\r\n \"apiVersion\": \"v1\",\r\n \"metadata\": {\r\n \"selfLink\": \"/api/v1/namespaces/default/pods\",\r\n \"resourceVersion\": \"1762810\"\r\n },\r\n \"items\": [\r\n {\r\n \"metadata\": {\r\n \"name\": \"nginx-1493591563-xb2v4\",\r\n \"generateName\": \"nginx-1493591563-\",\r\n \"namespace\": \"default\",\r\n \"selfLink\": \"/api/v1/namespaces/default/pods/nginx-1493591563-xb2v4\",\r\n \"uid\": \"ac1abb94-9c58-11e7-aaf5-00155d744505\",\r\n \"resourceVersion\": \"1737928\",\r\n \"creationTimestamp\": \"2017-09-18T10:03:51Z\",\r\n \"labels\": {\r\n \"app\": \"nginx\",\r\n \"pod-template-hash\": \"1493591563\"\r\n },\r\n \"annotations\": {\r\n \"kubernetes.io/created-by\": \"{\\\"kind\\\":\\\"SerializedReference\\\",\\\"apiVersion\\\":\\\"v1\\\",\\\"reference\\\":{\\\"kind\\\":\\\"ReplicaSet\\\",\\\"namespace\\\":\\\"default\\\",\\\"name\\\":\\\"nginx-1493591563\\\",\\\"uid\\\":\\\"ac013b63-9c58-11e7-aaf5-00155d744505\\\",\\\"apiVersion\\\":\\\"extensions\\\",\\\"resourceVersion\\\":\\\"5306\\\"}}\\n\"\r\n },\r\n \"ownerReferences\": [\r\n {\r\n \"apiVersion\": \"extensions/v1beta1\",\r\n \"kind\": \"ReplicaSet\",\r\n \"name\": \"nginx-1493591563\",\r\n \"uid\": \"ac013b63-9c58-11e7-aaf5-00155d744505\",\r\n \"controller\": true,\r\n \"blockOwnerDeletion\": true\r\n }\r\n ]\r\n },\r\n \"spec\": {\r\n \"volumes\": [\r\n {\r\n \"name\": \"default-token-3zzcj\",\r\n \"secret\": {\r\n \"secretName\": \"default-token-3zzcj\",\r\n \"defaultMode\": 420\r\n }\r\n }\r\n ],\r\n \"containers\": [\r\n {\r\n \"name\": \"nginx\",\r\n \"image\": \"nginx\",\r\n \"resources\": {},\r\n \"volumeMounts\": [\r\n {\r\n \"name\": \"default-token-3zzcj\",\r\n \"readOnly\": true,\r\n \"mountPath\": \"/var/run/secrets/kubernetes.io/serviceaccount\"\r\n }\r\n ],\r\n \"terminationMessagePath\": \"/dev/termination-log\",\r\n \"terminationMessagePolicy\": \"File\",\r\n \"imagePullPolicy\": \"Always\"\r\n }\r\n ],\r\n \"restartPolicy\": \"Always\",\r\n \"terminationGracePeriodSeconds\": 30,\r\n \"dnsPolicy\": \"ClusterFirst\",\r\n \"serviceAccountName\": \"default\",\r\n \"serviceAccount\": \"default\",\r\n \"nodeName\": \"ubuntu\",\r\n \"securityContext\": {},\r\n \"schedulerName\": \"default-scheduler\"\r\n },\r\n \"status\": {\r\n \"phase\": \"Running\",\r\n \"conditions\": [\r\n {\r\n \"type\": \"Initialized\",\r\n \"status\": \"True\",\r\n \"lastProbeTime\": null,\r\n \"lastTransitionTime\": \"2017-09-18T10:03:51Z\"\r\n },\r\n {\r\n \"type\": \"Ready\",\r\n \"status\": \"True\",\r\n \"lastProbeTime\": null,\r\n \"lastTransitionTime\": \"2017-10-12T07:09:21Z\"\r\n },\r\n {\r\n \"type\": \"PodScheduled\",\r\n \"status\": \"True\",\r\n \"lastProbeTime\": null,\r\n \"lastTransitionTime\": \"2017-09-18T10:03:51Z\"\r\n }\r\n ],\r\n \"hostIP\": \"192.168.188.42\",\r\n \"podIP\": \"172.17.0.5\",\r\n \"startTime\": \"2017-09-18T10:03:51Z\",\r\n \"containerStatuses\": [\r\n {\r\n \"name\": \"nginx\",\r\n \"state\": {\r\n \"running\": {\r\n \"startedAt\": \"2017-10-12T07:09:20Z\"\r\n }\r\n },\r\n \"lastState\": {\r\n \"terminated\": {\r\n \"exitCode\": 0,\r\n \"reason\": \"Completed\",\r\n \"startedAt\": \"2017-10-10T21:35:51Z\",\r\n \"finishedAt\": \"2017-10-12T07:07:37Z\",\r\n \"containerID\": \"docker://94df3f3965807421ad6dc76618e00b76cb15d024919c4946f3eb46a92659c62a\"\r\n }\r\n },\r\n \"ready\": true,\r\n \"restartCount\": 7,\r\n \"image\": \"nginx:latest\",\r\n \"imageID\": \"docker-pullable://nginx@sha256:004ac1d5e791e705f12a17c80d7bb1e8f7f01aa7dca7deee6e65a03465392072\",\r\n \"containerID\": \"docker://fa11bdd48c9b7d3a6c4c3f9b6d7319743c3455ab8d00c57d59c083b319b88194\"\r\n }\r\n ],\r\n \"qosClass\": \"BestEffort\"\r\n }\r\n }\r\n ]\r\n}"; private readonly IWebHost _webHost; - public MockKubeApiServer(ITestOutputHelper testOutput, Func> shouldNext = null, Action listenConfigure = null, + public MockKubeApiServer(ITestOutputHelper testOutput, Func> shouldNext = null, + Action listenConfigure = null, string resp = MockPodResponse) { shouldNext = shouldNext ?? (_ => Task.FromResult(true)); @@ -43,7 +43,9 @@ public MockKubeApiServer(ITestOutputHelper testOutput, Func buffer, WebSocketMessageType m { Buffer = buffer, MessageType = messageType, - EndOfMessage = endOfMessage + EndOfMessage = endOfMessage, }); this.receiveEvent.Set(); return Task.CompletedTask; } #region WebSocket overrides + public override WebSocketCloseStatus? CloseStatus => this.closeStatus; public override string CloseStatusDescription => this.closeStatusDescription; @@ -54,7 +55,8 @@ public override void Abort() throw new NotImplementedException(); } - public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) + public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, + CancellationToken cancellationToken) { this.closeStatus = closeStatus; this.closeStatusDescription = statusDescription; @@ -62,13 +64,14 @@ public override Task CloseAsync(WebSocketCloseStatus closeStatus, string statusD { Buffer = new ArraySegment(new byte[] { }), EndOfMessage = true, - MessageType = WebSocketMessageType.Close + MessageType = WebSocketMessageType.Close, }); this.receiveEvent.Set(); return Task.CompletedTask; } - public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken) + public override Task CloseOutputAsync(WebSocketCloseStatus closeStatus, string statusDescription, + CancellationToken cancellationToken) { throw new NotImplementedException(); } @@ -79,7 +82,8 @@ public override void Dispose() this.receiveEvent.Set(); } - public override async Task ReceiveAsync(ArraySegment buffer, CancellationToken cancellationToken) + public override async Task ReceiveAsync(ArraySegment buffer, + CancellationToken cancellationToken) { if (this.receiveBuffers.Count == 0) { @@ -113,19 +117,22 @@ public override async Task ReceiveAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken) + public override Task SendAsync(ArraySegment buffer, WebSocketMessageType messageType, bool endOfMessage, + CancellationToken cancellationToken) { - this.MessageSent?.Invoke(this, new MessageDataEventArgs() - { - Data = new MessageData() + this.MessageSent?.Invoke(this, + new MessageDataEventArgs() { - Buffer = buffer, - MessageType = messageType, - EndOfMessage = endOfMessage - } - }); + Data = new MessageData() + { + Buffer = buffer, + MessageType = messageType, + EndOfMessage = endOfMessage + }, + }); return Task.CompletedTask; } + #endregion public class MessageData diff --git a/tests/KubernetesClient.Tests/Mock/MockWebSocketBuilder.cs b/tests/KubernetesClient.Tests/Mock/MockWebSocketBuilder.cs index 34044c12e..d8933f212 100644 --- a/tests/KubernetesClient.Tests/Mock/MockWebSocketBuilder.cs +++ b/tests/KubernetesClient.Tests/Mock/MockWebSocketBuilder.cs @@ -1,5 +1,4 @@ #if !NETCOREAPP2_1 - using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -12,9 +11,11 @@ namespace k8s.Tests.Mock { public class MockWebSocketBuilder : WebSocketBuilder { - public Dictionary RequestHeaders { get; } = new Dictionary(); + public Dictionary RequestHeaders { get; } + = new Dictionary(); - public Collection Certificates { get; } = new Collection(); + public Collection Certificates { get; } + = new Collection(); public Uri Uri { get; private set; } @@ -28,7 +29,8 @@ public override WebSocketBuilder AddClientCertificate(X509Certificate2 certifica public override Task BuildAndConnectAsync(Uri uri, CancellationToken cancellationToken) { - this.Uri = uri; + this.Uri + = uri; return Task.FromResult(this.PublicWebSocket); } diff --git a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs index 1a3fe36f5..cece75ee8 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodExecController.cs @@ -22,7 +22,9 @@ public class PodExecController public PodExecController(WebSocketTestAdapter webSocketTestAdapter) { if (webSocketTestAdapter == null) + { throw new ArgumentNullException(nameof(webSocketTestAdapter)); + } WebSocketTestAdapter = webSocketTestAdapter; } @@ -45,11 +47,12 @@ public PodExecController(WebSocketTestAdapter webSocketTestAdapter) public async Task Exec(string kubeNamespace, string podName) { if (!HttpContext.WebSockets.IsWebSocketRequest) + { return BadRequest("Exec requires WebSockets"); + } WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync( - subProtocol: WebSocketProtocol.ChannelWebSocketProtocol - ); + subProtocol: WebSocketProtocol.ChannelWebSocketProtocol); WebSocketTestAdapter.AcceptedPodExecV1Connection.AcceptServerSocket(webSocket); diff --git a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs index 85b3673d9..64366829b 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/Controllers/PodPortForwardController.cs @@ -23,7 +23,9 @@ public class PodPortForwardController public PodPortForwardController(WebSocketTestAdapter webSocketTestAdapter) { if (webSocketTestAdapter == null) + { throw new ArgumentNullException(nameof(webSocketTestAdapter)); + } WebSocketTestAdapter = webSocketTestAdapter; } @@ -49,11 +51,12 @@ public PodPortForwardController(WebSocketTestAdapter webSocketTestAdapter) public async Task Exec(string kubeNamespace, string podName, IEnumerable ports) { if (!HttpContext.WebSockets.IsWebSocketRequest) + { return BadRequest("PortForward requires WebSockets"); + } WebSocket webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync( - subProtocol: WebSocketProtocol.ChannelWebSocketProtocol - ); + subProtocol: WebSocketProtocol.ChannelWebSocketProtocol); WebSocketTestAdapter.AcceptedPodPortForwardV1Connection.AcceptServerSocket(webSocket); diff --git a/tests/KubernetesClient.Tests/Mock/Server/Startup.cs b/tests/KubernetesClient.Tests/Mock/Server/Startup.cs index ce5ddc95b..c8297e08c 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/Startup.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/Startup.cs @@ -26,7 +26,9 @@ public Startup() public void ConfigureServices(IServiceCollection services) { if (services == null) + { throw new ArgumentNullException(nameof(services)); + } services.AddLogging(logging => { @@ -46,7 +48,7 @@ public void Configure(IApplicationBuilder app) app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(5), - ReceiveBufferSize = 2048 + ReceiveBufferSize = 2048, }); app.UseMvc(); } diff --git a/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs b/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs index 1cc11730b..25a0affe2 100644 --- a/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs +++ b/tests/KubernetesClient.Tests/Mock/Server/WebSocketTestAdapter.cs @@ -67,7 +67,9 @@ public class ServerSocketAcceptance public void AcceptServerSocket(WebSocket serverSocket) { if (serverSocket == null) + { throw new ArgumentNullException(nameof(serverSocket)); + } _completion.SetResult(serverSocket); } @@ -81,7 +83,9 @@ public void AcceptServerSocket(WebSocket serverSocket) public void RejectServerSocket(Exception reason) { if (reason == null) + { throw new ArgumentNullException(nameof(reason)); + } _completion.SetException(reason); } diff --git a/tests/KubernetesClient.Tests/ModelExtensionTests.cs b/tests/KubernetesClient.Tests/ModelExtensionTests.cs index e3bcf9910..2dd90613c 100644 --- a/tests/KubernetesClient.Tests/ModelExtensionTests.cs +++ b/tests/KubernetesClient.Tests/ModelExtensionTests.cs @@ -29,7 +29,13 @@ public void TestV1Status() s = new V1Status() { Status = "Failure", Code = 400, Message = "It's all messed up." }; Assert.Equal("BadRequest - It's all messed up.", s.ToString()); - s = new V1Status() { Status = "Failure", Code = 400, Reason = "IllegalValue", Message = "You're breaking the LAW!", }; + s = new V1Status() + { + Status = "Failure", + Code = 400, + Reason = "IllegalValue", + Message = "You're breaking the LAW!", + }; Assert.Equal("IllegalValue - You're breaking the LAW!", s.ToString()); } } diff --git a/tests/KubernetesClient.Tests/QuantityValueTests.cs b/tests/KubernetesClient.Tests/QuantityValueTests.cs index f9f0550c0..1f77be788 100644 --- a/tests/KubernetesClient.Tests/QuantityValueTests.cs +++ b/tests/KubernetesClient.Tests/QuantityValueTests.cs @@ -22,47 +22,33 @@ public void Parse() { foreach (var (input, expect) in new[] { - ("0", new ResourceQuantity(0, 0, DecimalSI)), - ("0n", new ResourceQuantity(0, 0, DecimalSI)), - ("0u", new ResourceQuantity(0, 0, DecimalSI)), - ("0m", new ResourceQuantity(0, 0, DecimalSI)), - ("0Ki", new ResourceQuantity(0, 0, BinarySI)), - ("0k", new ResourceQuantity(0, 0, DecimalSI)), - ("0Mi", new ResourceQuantity(0, 0, BinarySI)), - ("0M", new ResourceQuantity(0, 0, DecimalSI)), - ("0Gi", new ResourceQuantity(0, 0, BinarySI)), - ("0G", new ResourceQuantity(0, 0, DecimalSI)), - ("0Ti", new ResourceQuantity(0, 0, BinarySI)), - ("0T", new ResourceQuantity(0, 0, DecimalSI)), + ("0", new ResourceQuantity(0, 0, DecimalSI)), ("0n", new ResourceQuantity(0, 0, DecimalSI)), + ("0u", new ResourceQuantity(0, 0, DecimalSI)), ("0m", new ResourceQuantity(0, 0, DecimalSI)), + ("0Ki", new ResourceQuantity(0, 0, BinarySI)), ("0k", new ResourceQuantity(0, 0, DecimalSI)), + ("0Mi", new ResourceQuantity(0, 0, BinarySI)), ("0M", new ResourceQuantity(0, 0, DecimalSI)), + ("0Gi", new ResourceQuantity(0, 0, BinarySI)), ("0G", new ResourceQuantity(0, 0, DecimalSI)), + ("0Ti", new ResourceQuantity(0, 0, BinarySI)), ("0T", new ResourceQuantity(0, 0, DecimalSI)), // Quantity less numbers are allowed ("1", new ResourceQuantity(1, 0, DecimalSI)), // Binary suffixes - ("1Ki", new ResourceQuantity(1024, 0, BinarySI)), - ("8Ki", new ResourceQuantity(8 * 1024, 0, BinarySI)), + ("1Ki", new ResourceQuantity(1024, 0, BinarySI)), ("8Ki", new ResourceQuantity(8 * 1024, 0, BinarySI)), ("7Mi", new ResourceQuantity(7 * 1024 * 1024, 0, BinarySI)), ("6Gi", new ResourceQuantity(6L * 1024 * 1024 * 1024, 0, BinarySI)), ("5Ti", new ResourceQuantity(5L * 1024 * 1024 * 1024 * 1024, 0, BinarySI)), ("4Pi", new ResourceQuantity(4L * 1024 * 1024 * 1024 * 1024 * 1024, 0, BinarySI)), ("3Ei", new ResourceQuantity(3L * 1024 * 1024 * 1024 * 1024 * 1024 * 1024, 0, BinarySI)), - ("10Ti", new ResourceQuantity(10L * 1024 * 1024 * 1024 * 1024, 0, BinarySI)), ("100Ti", new ResourceQuantity(100L * 1024 * 1024 * 1024 * 1024, 0, BinarySI)), // Decimal suffixes - ("5n", new ResourceQuantity(5, -9, DecimalSI)), - ("4u", new ResourceQuantity(4, -6, DecimalSI)), - ("3m", new ResourceQuantity(3, -3, DecimalSI)), - ("9", new ResourceQuantity(9, 0, DecimalSI)), - ("8k", new ResourceQuantity(8, 3, DecimalSI)), - ("50k", new ResourceQuantity(5, 4, DecimalSI)), - ("7M", new ResourceQuantity(7, 6, DecimalSI)), - ("6G", new ResourceQuantity(6, 9, DecimalSI)), - ("5T", new ResourceQuantity(5, 12, DecimalSI)), - ("40T", new ResourceQuantity(4, 13, DecimalSI)), - ("300T", new ResourceQuantity(3, 14, DecimalSI)), - ("2P", new ResourceQuantity(2, 15, DecimalSI)), + ("5n", new ResourceQuantity(5, -9, DecimalSI)), ("4u", new ResourceQuantity(4, -6, DecimalSI)), + ("3m", new ResourceQuantity(3, -3, DecimalSI)), ("9", new ResourceQuantity(9, 0, DecimalSI)), + ("8k", new ResourceQuantity(8, 3, DecimalSI)), ("50k", new ResourceQuantity(5, 4, DecimalSI)), + ("7M", new ResourceQuantity(7, 6, DecimalSI)), ("6G", new ResourceQuantity(6, 9, DecimalSI)), + ("5T", new ResourceQuantity(5, 12, DecimalSI)), ("40T", new ResourceQuantity(4, 13, DecimalSI)), + ("300T", new ResourceQuantity(3, 14, DecimalSI)), ("2P", new ResourceQuantity(2, 15, DecimalSI)), ("1E", new ResourceQuantity(1, 18, DecimalSI)), // Decimal exponents @@ -81,12 +67,9 @@ public void Parse() ("100.035k", new ResourceQuantity(100035, 0, DecimalSI)), // Things that look like floating point - ("0.001", new ResourceQuantity(1, -3, DecimalSI)), - ("0.0005k", new ResourceQuantity(5, -1, DecimalSI)), - ("0.005", new ResourceQuantity(5, -3, DecimalSI)), - ("0.05", new ResourceQuantity(5, -2, DecimalSI)), - ("0.5", new ResourceQuantity(5, -1, DecimalSI)), - ("0.00050k", new ResourceQuantity(5, -1, DecimalSI)), + ("0.001", new ResourceQuantity(1, -3, DecimalSI)), ("0.0005k", new ResourceQuantity(5, -1, DecimalSI)), + ("0.005", new ResourceQuantity(5, -3, DecimalSI)), ("0.05", new ResourceQuantity(5, -2, DecimalSI)), + ("0.5", new ResourceQuantity(5, -1, DecimalSI)), ("0.00050k", new ResourceQuantity(5, -1, DecimalSI)), ("0.00500", new ResourceQuantity(5, -3, DecimalSI)), ("0.05000", new ResourceQuantity(5, -2, DecimalSI)), ("0.50000", new ResourceQuantity(5, -1, DecimalSI)), @@ -95,23 +78,19 @@ public void Parse() ("0.5e-2", new ResourceQuantity(5, -3, DecimalExponent)), ("0.5e0", new ResourceQuantity(5, -1, DecimalExponent)), ("10.035M", new ResourceQuantity(10035, 3, DecimalSI)), - ("1.2e3", new ResourceQuantity(12, 2, DecimalExponent)), ("1.3E+6", new ResourceQuantity(13, 5, DecimalExponent)), ("1.40e9", new ResourceQuantity(14, 8, DecimalExponent)), ("1.53E12", new ResourceQuantity(153, 10, DecimalExponent)), ("1.6e15", new ResourceQuantity(16, 14, DecimalExponent)), ("1.7E18", new ResourceQuantity(17, 17, DecimalExponent)), - - ("9.01", new ResourceQuantity(901, -2, DecimalSI)), - ("8.1k", new ResourceQuantity(81, 2, DecimalSI)), + ("9.01", new ResourceQuantity(901, -2, DecimalSI)), ("8.1k", new ResourceQuantity(81, 2, DecimalSI)), ("7.123456M", new ResourceQuantity(7123456, 0, DecimalSI)), ("6.987654321G", new ResourceQuantity(6987654321, 0, DecimalSI)), ("5.444T", new ResourceQuantity(5444, 9, DecimalSI)), ("40.1T", new ResourceQuantity(401, 11, DecimalSI)), ("300.2T", new ResourceQuantity(3002, 11, DecimalSI)), - ("2.5P", new ResourceQuantity(25, 14, DecimalSI)), - ("1.01E", new ResourceQuantity(101, 16, DecimalSI)), + ("2.5P", new ResourceQuantity(25, 14, DecimalSI)), ("1.01E", new ResourceQuantity(101, 16, DecimalSI)), // Things that saturate/round ("3.001n", new ResourceQuantity(4, -9, DecimalSI)), @@ -135,10 +114,8 @@ public void Parse() // Things written by trolls ("0.000000000001Ki", new ResourceQuantity(2, -9, DecimalSI)), // rounds up, changes format - (".001", new ResourceQuantity(1, -3, DecimalSI)), - (".0001k", new ResourceQuantity(100, -3, DecimalSI)), - ("1.", new ResourceQuantity(1, 0, DecimalSI)), - ("1.G", new ResourceQuantity(1, 9, DecimalSI)) + (".001", new ResourceQuantity(1, -3, DecimalSI)), (".0001k", new ResourceQuantity(100, -3, DecimalSI)), + ("1.", new ResourceQuantity(1, 0, DecimalSI)), ("1.G", new ResourceQuantity(1, 9, DecimalSI)), }) { Assert.Equal(expect.ToString(), new ResourceQuantity(input).ToString()); @@ -146,15 +123,7 @@ public void Parse() foreach (var s in new[] { - "1.1.M", - "1+1.0M", - "0.1mi", - "0.1am", - "aoeu", - ".5i", - "1i", - "-3.01i", - "-3.01e-" + "1.1.M", "1+1.0M", "0.1mi", "0.1am", "aoeu", ".5i", "1i", "-3.01i", "-3.01e-", // TODO support trailing whitespace is forbidden // " 1", @@ -198,8 +167,7 @@ public void QuantityString() (new ResourceQuantity(1234567, -3, BinarySI), "1234567m", ""), (new ResourceQuantity(3, 3, DecimalSI), "3k", ""), (new ResourceQuantity(1025, 0, BinarySI), "1025", ""), - (new ResourceQuantity(0, 0, DecimalSI), "0", ""), - (new ResourceQuantity(0, 0, BinarySI), "0", ""), + (new ResourceQuantity(0, 0, DecimalSI), "0", ""), (new ResourceQuantity(0, 0, BinarySI), "0", ""), (new ResourceQuantity(1, 9, DecimalExponent), "1e9", ".001e12"), (new ResourceQuantity(1, -3, DecimalExponent), "1e-3", "0.001e0"), (new ResourceQuantity(1, -9, DecimalExponent), "1e-9", "1000e-12"), @@ -217,7 +185,7 @@ public void QuantityString() (new ResourceQuantity(10800, -10, DecimalSI), "1080n", ""), (new ResourceQuantity(1, -6, DecimalSI), "1u", ""), (new ResourceQuantity(80, -6, DecimalSI), "80u", ""), - (new ResourceQuantity(1080, -6, DecimalSI), "1080u", "") + (new ResourceQuantity(1080, -6, DecimalSI), "1080u", ""), }) { Assert.Equal(expect, input.ToString()); diff --git a/tests/KubernetesClient.Tests/StreamDemuxerTests.cs b/tests/KubernetesClient.Tests/StreamDemuxerTests.cs index 268957e56..81df910f6 100644 --- a/tests/KubernetesClient.Tests/StreamDemuxerTests.cs +++ b/tests/KubernetesClient.Tests/StreamDemuxerTests.cs @@ -27,10 +27,7 @@ public async Task SendDataRemoteCommand() using (StreamDemuxer demuxer = new StreamDemuxer(ws)) { List sentBuffer = new List(); - ws.MessageSent += (sender, args) => - { - sentBuffer.AddRange(args.Data.Buffer); - }; + ws.MessageSent += (sender, args) => { sentBuffer.AddRange(args.Data.Buffer); }; demuxer.Start(); @@ -40,7 +37,8 @@ public async Task SendDataRemoteCommand() stream.Write(b, 0, b.Length); // Send 100 bytes, expect 1 (channel index) + 100 (payload) = 101 bytes - Assert.True(await WaitForAsync(() => sentBuffer.Count == 101), $"Demuxer error: expect to send 101 bytes, but actually send {sentBuffer.Count} bytes."); + Assert.True(await WaitForAsync(() => sentBuffer.Count == 101), + $"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!"); } @@ -53,10 +51,7 @@ public async Task SendMultipleDataRemoteCommand() using (StreamDemuxer demuxer = new StreamDemuxer(ws)) { List sentBuffer = new List(); - ws.MessageSent += (sender, args) => - { - sentBuffer.AddRange(args.Data.Buffer); - }; + ws.MessageSent += (sender, args) => { sentBuffer.AddRange(args.Data.Buffer); }; demuxer.Start(); @@ -68,7 +63,8 @@ public async Task SendMultipleDataRemoteCommand() 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), $"Demuxer error: expect to send 302 bytes, but actually send {sentBuffer.Count} bytes."); + Assert.True(await WaitForAsync(() => sentBuffer.Count == 302), + $"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!"); Assert.True(sentBuffer[101] == channelIndex, "The second message first byte is not channel index!"); @@ -93,9 +89,15 @@ public async Task ReceiveDataRemoteCommand() var t = Task.Run(async () => { - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xAA, false)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(200, channelIndex, 0xAB, false)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xAC, false)), WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xAA, false)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(200, channelIndex, 0xAB, false)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xAC, false)), + WebSocketMessageType.Binary, true); await WaitForAsync(() => receivedBuffer.Count == expectedCount); await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); @@ -108,14 +110,17 @@ public async Task ReceiveDataRemoteCommand() { break; } + for (int i = 0; i < cRead; i++) { receivedBuffer.Add(buffer[i]); } } + await t; - Assert.True(receivedBuffer.Count == expectedCount, $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); + Assert.True(receivedBuffer.Count == expectedCount, + $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); Assert.True(receivedBuffer[0] == 0xAA, "The first payload incorrect!"); Assert.True(receivedBuffer[98] == 0xAA, "The first payload incorrect!"); Assert.True(receivedBuffer[99] == 0xAB, "The second payload incorrect!"); @@ -143,9 +148,15 @@ public async Task ReceiveDataPortForward() var t = Task.Run(async () => { - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xB1, true)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(200, channelIndex, 0xB2, false)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xB3, false)), WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xB1, true)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(200, channelIndex, 0xB2, false)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xB3, false)), + WebSocketMessageType.Binary, true); await WaitForAsync(() => receivedBuffer.Count == expectedCount); await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); @@ -158,14 +169,17 @@ public async Task ReceiveDataPortForward() { break; } + for (int i = 0; i < cRead; i++) { receivedBuffer.Add(buffer[i]); } } + await t; - Assert.True(receivedBuffer.Count == expectedCount, $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); + Assert.True(receivedBuffer.Count == expectedCount, + $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); Assert.True(receivedBuffer[0] == 0xB1, "The first payload incorrect!"); Assert.True(receivedBuffer[96] == 0xB1, "The first payload incorrect!"); Assert.True(receivedBuffer[97] == 0xB2, "The second payload incorrect!"); @@ -193,9 +207,15 @@ public async Task ReceiveDataPortForwardOneByteMessage() var t = Task.Run(async () => { - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(2, channelIndex, 0xC1, true)), WebSocketMessageType.Binary, false); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xC2, false)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xC3, false)), WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(2, channelIndex, 0xC1, true)), + WebSocketMessageType.Binary, false); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(100, channelIndex, 0xC2, false)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(300, channelIndex, 0xC3, false)), + WebSocketMessageType.Binary, true); await WaitForAsync(() => receivedBuffer.Count == expectedCount); await ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "normal", CancellationToken.None); @@ -208,14 +228,17 @@ public async Task ReceiveDataPortForwardOneByteMessage() { break; } + for (int i = 0; i < cRead; i++) { receivedBuffer.Add(buffer[i]); } } + await t; - Assert.True(receivedBuffer.Count == expectedCount, $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); + Assert.True(receivedBuffer.Count == expectedCount, + $"Demuxer error: expect to receive {expectedCount} bytes, but actually got {receivedBuffer.Count} bytes."); Assert.True(receivedBuffer[0] == 0xC2, "The first payload incorrect!"); Assert.True(receivedBuffer[98] == 0xC2, "The first payload incorrect!"); Assert.True(receivedBuffer[99] == 0xC3, "The second payload incorrect!"); @@ -247,9 +270,15 @@ public async Task ReceiveDataRemoteCommandMultipleStream() var t1 = Task.Run(async () => { // Simulate WebSocket received remote data to multiple streams - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(100, channelIndex1, 0xD1, false)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(200, channelIndex2, 0xD2, false)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(300, channelIndex1, 0xD3, false)), WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(100, channelIndex1, 0xD1, false)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(200, channelIndex2, 0xD2, false)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(300, channelIndex1, 0xD3, false)), + WebSocketMessageType.Binary, true); await WaitForAsync(() => receivedBuffer1.Count == expectedCount1); await WaitForAsync(() => receivedBuffer2.Count == expectedCount2); @@ -265,6 +294,7 @@ public async Task ReceiveDataRemoteCommandMultipleStream() { break; } + for (int i = 0; i < cRead; i++) { receivedBuffer1.Add(buffer[i]); @@ -281,6 +311,7 @@ public async Task ReceiveDataRemoteCommandMultipleStream() { break; } + for (int i = 0; i < cRead; i++) { receivedBuffer2.Add(buffer[i]); @@ -289,8 +320,10 @@ public async Task ReceiveDataRemoteCommandMultipleStream() }); await Task.WhenAll(t1, t2, t3); - Assert.True(receivedBuffer1.Count == expectedCount1, $"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes."); - Assert.True(receivedBuffer2.Count == expectedCount2, $"Demuxer error: expect to receive {expectedCount2} bytes, but actually got {receivedBuffer2.Count} bytes."); + Assert.True(receivedBuffer1.Count == expectedCount1, + $"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes."); + Assert.True(receivedBuffer2.Count == expectedCount2, + $"Demuxer error: expect to receive {expectedCount2} bytes, but actually got {receivedBuffer2.Count} bytes."); Assert.True(receivedBuffer1[0] == 0xD1, "The first payload incorrect!"); Assert.True(receivedBuffer1[98] == 0xD1, "The first payload incorrect!"); Assert.True(receivedBuffer1[99] == 0xD3, "The second payload incorrect!"); @@ -326,9 +359,15 @@ public async Task ReceiveDataPortForwardMultipleStream() var t1 = Task.Run(async () => { // Simulate WebSocket received remote data to multiple streams - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(100, channelIndex1, 0xE1, true)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(200, channelIndex2, 0xE2, true)), WebSocketMessageType.Binary, true); - await ws.InvokeReceiveAsync(new ArraySegment(GenerateRandomBuffer(300, channelIndex1, 0xE3, false)), WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(100, channelIndex1, 0xE1, true)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(200, channelIndex2, 0xE2, true)), + WebSocketMessageType.Binary, true); + await ws.InvokeReceiveAsync( + new ArraySegment(GenerateRandomBuffer(300, channelIndex1, 0xE3, false)), + WebSocketMessageType.Binary, true); await WaitForAsync(() => receivedBuffer1.Count == expectedCount1); await WaitForAsync(() => receivedBuffer2.Count == expectedCount2); @@ -344,6 +383,7 @@ public async Task ReceiveDataPortForwardMultipleStream() { break; } + for (int i = 0; i < cRead; i++) { receivedBuffer1.Add(buffer[i]); @@ -360,6 +400,7 @@ public async Task ReceiveDataPortForwardMultipleStream() { break; } + for (int i = 0; i < cRead; i++) { receivedBuffer2.Add(buffer[i]); @@ -368,8 +409,10 @@ public async Task ReceiveDataPortForwardMultipleStream() }); await Task.WhenAll(t1, t2, t3); - Assert.True(receivedBuffer1.Count == expectedCount1, $"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes."); - Assert.True(receivedBuffer2.Count == expectedCount2, $"Demuxer error: expect to receive {expectedCount2} bytes, but actually got {receivedBuffer2.Count} bytes."); + Assert.True(receivedBuffer1.Count == expectedCount1, + $"Demuxer error: expect to receive {expectedCount1} bytes, but actually got {receivedBuffer1.Count} bytes."); + Assert.True(receivedBuffer2.Count == expectedCount2, + $"Demuxer error: expect to receive {expectedCount2} bytes, but actually got {receivedBuffer2.Count} bytes."); Assert.True(receivedBuffer1[0] == 0xE1, "The first payload incorrect!"); Assert.True(receivedBuffer1[96] == 0xE1, "The first payload incorrect!"); Assert.True(receivedBuffer1[97] == 0xE3, "The second payload incorrect!"); @@ -387,13 +430,15 @@ private static byte[] GenerateRandomBuffer(int length, byte channelIndex, byte c { if (length > 1) { - buffer[1] = 0xFF; // the first port bytes + buffer[1] = 0xFF; // the first port bytes } + if (length > 2) { - buffer[2] = 0xFF; // the 2nd port bytes + buffer[2] = 0xFF; // the 2nd port bytes } } + return buffer; } @@ -404,6 +449,7 @@ private static byte[] GenerateRandomBuffer(int length, byte content) { buffer[i] = content; } + return buffer; } @@ -418,8 +464,10 @@ private async Task WaitForAsync(Func handler, float waitForSeconds = { return true; } + await Task.Delay(10); } while (w.Elapsed.Duration().TotalSeconds < waitForSeconds); + return false; } finally diff --git a/tests/KubernetesClient.Tests/TaskAssert.cs b/tests/KubernetesClient.Tests/TaskAssert.cs index 142007d2b..488b8adcf 100644 --- a/tests/KubernetesClient.Tests/TaskAssert.cs +++ b/tests/KubernetesClient.Tests/TaskAssert.cs @@ -15,8 +15,7 @@ public static void NotCompleted(Task task, string message = "Task should not be public static async Task Completed(Task task, TimeSpan timeout, string message = "Task timed out") { var timeoutTask = Task.Delay( - TimeSpan.FromMilliseconds(1000) - ); + TimeSpan.FromMilliseconds(1000)); var completedTask = await Task.WhenAny(task, timeoutTask); Assert.True(ReferenceEquals(task, completedTask), message); @@ -28,11 +27,10 @@ public static async Task Completed(Task task, TimeSpan timeout, string { 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. - ); + 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 completedTask = await Task.WhenAny(task, timeoutTask); Assert.True(ReferenceEquals(task, completedTask), message); diff --git a/tests/KubernetesClient.Tests/V1StatusObjectViewTests.cs b/tests/KubernetesClient.Tests/V1StatusObjectViewTests.cs index 0e3abf34c..d05849fa7 100644 --- a/tests/KubernetesClient.Tests/V1StatusObjectViewTests.cs +++ b/tests/KubernetesClient.Tests/V1StatusObjectViewTests.cs @@ -18,18 +18,11 @@ public V1StatusObjectViewTests(ITestOutputHelper testOutput) [Fact] public void ReturnStatus() { - var v1Status = new V1Status - { - Message = "test message", - Status = "test status" - }; + var v1Status = new V1Status { Message = "test message", Status = "test status" }; using (var server = new MockKubeApiServer(testOutput, resp: JsonConvert.SerializeObject(v1Status))) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var status = client.DeleteNamespace("test", new V1DeleteOptions()); @@ -44,22 +37,13 @@ public void ReturnObject() { var corev1Namespace = new V1Namespace() { - Metadata = new V1ObjectMeta() - { - Name = "test name" - }, - Status = new V1NamespaceStatus() - { - Phase = "test termating" - } + Metadata = new V1ObjectMeta() { Name = "test name" }, + Status = new V1NamespaceStatus() { Phase = "test termating" }, }; using (var server = new MockKubeApiServer(testOutput, resp: JsonConvert.SerializeObject(corev1Namespace))) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var status = client.DeleteNamespace("test", new V1DeleteOptions()); @@ -70,7 +54,6 @@ public void ReturnObject() Assert.Equal(obj.Metadata.Name, corev1Namespace.Metadata.Name); Assert.Equal(obj.Status.Phase, corev1Namespace.Status.Phase); } - } } } diff --git a/tests/KubernetesClient.Tests/WatchTests.cs b/tests/KubernetesClient.Tests/WatchTests.cs index 1675847e0..97a98a8db 100644 --- a/tests/KubernetesClient.Tests/WatchTests.cs +++ b/tests/KubernetesClient.Tests/WatchTests.cs @@ -40,11 +40,9 @@ public WatchTests(ITestOutputHelper testOutput) private static string BuildWatchEventStreamLine(WatchEventType eventType) { var corev1PodList = JsonConvert.DeserializeObject(MockKubeApiServer.MockPodResponse); - return JsonConvert.SerializeObject(new Watcher.WatchEvent - { - Type = eventType, - Object = corev1PodList.Items.First() - }, new StringEnumConverter()); + return JsonConvert.SerializeObject( + new Watcher.WatchEvent { Type = eventType, Object = corev1PodList.Items.First() }, + new StringEnumConverter()); } private static async Task WriteStreamLine(HttpContext httpContext, string reponseLine) @@ -60,19 +58,15 @@ public async Task CannotWatch() { using (var server = new MockKubeApiServer(testOutput: testOutput)) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); // did not pass watch param var listTask = client.ListNamespacedPodWithHttpMessagesAsync("default"); var onErrorCalled = false; - using (listTask.Watch((type, item) => { }, e => + using (listTask.Watch((type, item) => { }, e => { onErrorCalled = true; })) { - onErrorCalled = true; - })) { } + } await Task.Delay(TimeSpan.FromSeconds(1)); // delay for onerror to be called Assert.True(onErrorCalled); @@ -103,17 +97,11 @@ public async Task AsyncWatcher() return false; })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); - using (listTask.Watch((type, item) => - { - eventsReceived.Set(); - })) + using (listTask.Watch((type, item) => { eventsReceived.Set(); })) { // here watcher is ready to use, but http server has not responsed yet. created.Set(); @@ -151,10 +139,7 @@ public async Task SuriveBadLine() return false; })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); @@ -176,16 +161,14 @@ public async Task SuriveBadLine() errors += 1; eventsReceived.Signal(); }, - onClosed: connectionClosed.Set - ); + onClosed: connectionClosed.Set); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, - "Timed out waiting for all events / errors to be received." - ); + "Timed out waiting for all events / errors to be received."); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Modified, events); @@ -221,10 +204,7 @@ public async Task DisposeWatch() return true; })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); @@ -236,15 +216,13 @@ public async Task DisposeWatch() events.Add(type); eventsReceived.Signal(); }, - onClosed: connectionClosed.Set - ); + onClosed: connectionClosed.Set); // wait at least an event await Task.WhenAny(Task.Run(() => eventsReceived.Wait()), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, - "Timed out waiting for events." - ); + "Timed out waiting for events."); Assert.NotEmpty(events); Assert.True(watcher.Watching); @@ -271,7 +249,8 @@ public async Task DisposeWatch() [Fact] public async Task WatchAllEvents() { - AsyncCountdownEvent eventsReceived = new AsyncCountdownEvent(4 /* first line of response is eaten by WatcherDelegatingHandler */); + AsyncCountdownEvent eventsReceived = + new AsyncCountdownEvent(4 /* first line of response is eaten by WatcherDelegatingHandler */); AsyncManualResetEvent serverShutdown = new AsyncManualResetEvent(); var waitForClosed = new AsyncManualResetEvent(false); @@ -287,10 +266,7 @@ public async Task WatchAllEvents() return false; })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); @@ -312,16 +288,14 @@ public async Task WatchAllEvents() errors += 1; eventsReceived.Signal(); }, - onClosed: waitForClosed.Set - ); + onClosed: waitForClosed.Set); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, - "Timed out waiting for all events / errors to be received." - ); + "Timed out waiting for all events / errors to be received."); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); @@ -361,10 +335,7 @@ public async Task WatchEventsWithTimeout() return false; })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); @@ -386,16 +357,14 @@ public async Task WatchEventsWithTimeout() errors += 1; eventsReceived.Signal(); }, - onClosed: connectionClosed.Set - ); + onClosed: connectionClosed.Set); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, - "Timed out waiting for all events / errors to be received." - ); + "Timed out waiting for all events / errors to be received."); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); @@ -428,10 +397,7 @@ public async Task WatchServerDisconnect() throw new IOException("server down"); })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var listTask = await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true); @@ -451,8 +417,7 @@ public async Task WatchServerDisconnect() Assert.True( exceptionReceived.IsSet, - "Timed out waiting for exception" - ); + "Timed out waiting for exception"); await Task.WhenAny(waitForClosed.WaitAsync(), Task.Delay(TestTimeout)); Assert.True(waitForClosed.IsSet); @@ -492,10 +457,8 @@ public async Task TestWatchWithHandlers() var handler1 = new DummyHandler(); var handler2 = new DummyHandler(); - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }, handler1, handler2); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }, handler1, + handler2); Assert.False(handler1.Called); Assert.False(handler2.Called); @@ -509,16 +472,14 @@ public async Task TestWatchWithHandlers() { events.Add(type); eventsReceived.Signal(); - } - ); + }); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, - "Timed out waiting for all events / errors to be received." - ); + "Timed out waiting for all events / errors to be received."); Assert.Contains(WatchEventType.Added, events); @@ -548,10 +509,7 @@ public async Task DirectWatchAllEvents() return false; })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var events = new HashSet(); var errors = 0; @@ -560,31 +518,29 @@ public async Task DirectWatchAllEvents() name: "myPod", @namespace: "default", onEvent: - (type, item) => - { - testOutput.WriteLine($"Watcher received '{type}' event."); + (type, item) => + { + testOutput.WriteLine($"Watcher received '{type}' event."); - events.Add(type); - eventsReceived.Signal(); - }, + events.Add(type); + eventsReceived.Signal(); + }, onError: - error => - { - testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); + error => + { + testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); - errors += 1; - eventsReceived.Signal(); - }, - onClosed: connectionClosed.Set - ); + errors += 1; + eventsReceived.Signal(); + }, + onClosed: connectionClosed.Set); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, - "Timed out waiting for all events / errors to be received." - ); + "Timed out waiting for all events / errors to be received."); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); @@ -605,7 +561,9 @@ public async Task DirectWatchAllEvents() [Fact(Skip = "Integration Test")] public async Task WatcherIntegrationTest() { - var kubernetesConfig = KubernetesClientConfiguration.BuildConfigFromConfigFile(kubeconfigPath: @"C:\Users\frede\Source\Repos\cloud\minikube.config"); + var kubernetesConfig = + KubernetesClientConfiguration.BuildConfigFromConfigFile( + kubeconfigPath: @"C:\Users\frede\Source\Repos\cloud\minikube.config"); var kubernetes = new Kubernetes(kubernetesConfig); var job = await kubernetes.CreateNamespacedJobAsync( @@ -613,13 +571,9 @@ public async Task WatcherIntegrationTest() { ApiVersion = "batch/v1", Kind = V1Job.KubeKind, - Metadata = new V1ObjectMeta() - { - Name = nameof(WatcherIntegrationTest).ToLowerInvariant() - }, + Metadata = new V1ObjectMeta() { Name = nameof(WatcherIntegrationTest).ToLowerInvariant() }, Spec = new V1JobSpec() { - Template = new V1PodTemplateSpec() { Spec = new V1PodSpec() @@ -630,12 +584,7 @@ public async Task WatcherIntegrationTest() { Image = "ubuntu/xenial", Name = "runner", - Command = new List() - { - "/bin/bash", - "-c", - "--" - }, + Command = new List() {"/bin/bash", "-c", "--" }, Args = new List() { "trap : TERM INT; sleep infinity & wait" @@ -645,7 +594,7 @@ public async Task WatcherIntegrationTest() RestartPolicy = "Never" }, } - } + }, }, "default"); @@ -699,10 +648,7 @@ public async Task DirectWatchEventsWithTimeout() return false; })) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var events = new HashSet(); var errors = 0; @@ -711,30 +657,28 @@ public async Task DirectWatchEventsWithTimeout() name: "myPod", @namespace: "default", onEvent: - (type, item) => - { - testOutput.WriteLine($"Watcher received '{type}' event."); + (type, item) => + { + testOutput.WriteLine($"Watcher received '{type}' event."); - events.Add(type); - eventsReceived.Signal(); - }, + events.Add(type); + eventsReceived.Signal(); + }, onError: - error => - { - testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); + error => + { + testOutput.WriteLine($"Watcher received '{error.GetType().FullName}' error."); - errors += 1; - eventsReceived.Signal(); - } - ); + errors += 1; + eventsReceived.Signal(); + }); // wait server yields all events await Task.WhenAny(eventsReceived.WaitAsync(), Task.Delay(TestTimeout)); Assert.True( eventsReceived.CurrentCount == 0, - "Timed out waiting for all events / errors to be received." - ); + "Timed out waiting for all events / errors to be received."); Assert.Contains(WatchEventType.Added, events); Assert.Contains(WatchEventType.Deleted, events); @@ -763,17 +707,15 @@ public async Task WatchShouldCancelAfterRequested() return true; }, resp: "")) { - var client = new Kubernetes(new KubernetesClientConfiguration - { - Host = server.Uri.ToString() - }); + var client = new Kubernetes(new KubernetesClientConfiguration { Host = server.Uri.ToString() }); var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(2)); await Assert.ThrowsAnyAsync(async () => { - await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true, cancellationToken: cts.Token); + await client.ListNamespacedPodWithHttpMessagesAsync("default", watch: true, + cancellationToken: cts.Token); }); } } diff --git a/tests/KubernetesClient.Tests/WatcherTests.cs b/tests/KubernetesClient.Tests/WatcherTests.cs index 5e8c9b7ce..0a8b8bcd5 100644 --- a/tests/KubernetesClient.Tests/WatcherTests.cs +++ b/tests/KubernetesClient.Tests/WatcherTests.cs @@ -13,7 +13,8 @@ public class WatcherTests [Fact] public void ReadError() { - byte[] data = Encoding.UTF8.GetBytes("{\"type\":\"ERROR\",\"object\":{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"too old resource version: 44982(53593)\",\"reason\":\"Gone\",\"code\":410}}"); + byte[] data = Encoding.UTF8.GetBytes( + "{\"type\":\"ERROR\",\"object\":{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"message\":\"too old resource version: 44982(53593)\",\"reason\":\"Gone\",\"code\":410}}"); using (MemoryStream stream = new MemoryStream(data)) using (StreamReader reader = new StreamReader(stream)) diff --git a/tests/KubernetesClient.Tests/WebSocketTestBase.cs b/tests/KubernetesClient.Tests/WebSocketTestBase.cs index 03dde8e9e..d66571602 100644 --- a/tests/KubernetesClient.Tests/WebSocketTestBase.cs +++ b/tests/KubernetesClient.Tests/WebSocketTestBase.cs @@ -42,8 +42,7 @@ protected WebSocketTestBase(ITestOutputHelper testOutput) // Useful to diagnose test timeouts. TestCancellation.Register( - () => testOutput.WriteLine("Test-level cancellation token has been canceled.") - ); + () => testOutput.WriteLine("Test-level cancellation token has been canceled.")); ServerBaseAddress = new Uri($"http://localhost:{port}"); WebSocketBaseAddress = new Uri($"ws://localhost:{port}"); @@ -96,7 +95,9 @@ protected WebSocketTestBase(ITestOutputHelper testOutput) protected virtual void ConfigureTestServerServices(IServiceCollection services) { if (services == null) + { throw new ArgumentNullException(nameof(services)); + } // Inject WebSocketTestData. services.AddSingleton(WebSocketTestAdapter); @@ -111,7 +112,9 @@ protected virtual void ConfigureTestServerServices(IServiceCollection services) protected virtual void ConfigureTestServerLogging(ILoggingBuilder logging) { if (logging == null) + { throw new ArgumentNullException(nameof(logging)); + } logging.ClearProviders(); // Don't log to console. logging.AddTestOutput(this.testOutput, LogLevel.Information); @@ -128,10 +131,7 @@ protected virtual void ConfigureTestServerLogging(ILoggingBuilder logging) /// protected virtual Kubernetes CreateTestClient(ServiceClientCredentials credentials = null) { - return new Kubernetes(credentials ?? AnonymousClientCredentials.Instance) - { - BaseUri = ServerBaseAddress - }; + return new Kubernetes(credentials ?? AnonymousClientCredentials.Instance) { BaseUri = ServerBaseAddress }; } /// @@ -156,13 +156,19 @@ protected virtual Kubernetes CreateTestClient(ServiceClientCredentials credentia /// /// A representing the asynchronous operation. /// - protected async Task Disconnect(WebSocket clientSocket, WebSocket serverSocket, WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure, string closeStatusDescription = "Normal Closure") + protected async Task Disconnect(WebSocket clientSocket, WebSocket serverSocket, + WebSocketCloseStatus closeStatus = WebSocketCloseStatus.NormalClosure, + string closeStatusDescription = "Normal Closure") { if (clientSocket == null) + { throw new ArgumentNullException(nameof(clientSocket)); + } if (serverSocket == null) + { throw new ArgumentNullException(nameof(serverSocket)); + } testOutput.WriteLine("Disconnecting..."); @@ -172,22 +178,28 @@ protected async Task Disconnect(WebSocket clientSocket, WebSocket serverSocket, .ContinueWith(async received => { if (received.IsFaulted) - testOutput.WriteLine("Server socket operation to receive Close message failed: {0}", received.Exception.Flatten().InnerExceptions[0]); + { + testOutput.WriteLine("Server socket operation to receive Close message failed: {0}", + received.Exception.Flatten().InnerExceptions[0]); + } else if (received.IsCanceled) + { testOutput.WriteLine("Server socket operation to receive Close message was canceled."); + } else { - testOutput.WriteLine($"Received {received.Result.MessageType} message from server socket (expecting {WebSocketMessageType.Close})."); + testOutput.WriteLine( + $"Received {received.Result.MessageType} message from server socket (expecting {WebSocketMessageType.Close})."); if (received.Result.MessageType == WebSocketMessageType.Close) { - testOutput.WriteLine($"Closing server socket (with status {received.Result.CloseStatus})..."); + testOutput.WriteLine( + $"Closing server socket (with status {received.Result.CloseStatus})..."); await serverSocket.CloseAsync( received.Result.CloseStatus.Value, received.Result.CloseStatusDescription, - TestCancellation - ); + TestCancellation); testOutput.WriteLine("Server socket closed."); } @@ -231,10 +243,14 @@ await serverSocket.CloseAsync( protected async Task SendMultiplexed(WebSocket webSocket, byte streamIndex, string text) { if (webSocket == null) + { throw new ArgumentNullException(nameof(webSocket)); + } if (text == null) + { throw new ArgumentNullException(nameof(text)); + } byte[] payload = Encoding.ASCII.GetBytes(text); byte[] sendBuffer = new byte[payload.Length + 1]; @@ -244,8 +260,7 @@ protected async Task SendMultiplexed(WebSocket webSocket, byte streamIndex, await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Binary, endOfMessage: true, - cancellationToken: TestCancellation - ); + cancellationToken: TestCancellation); return sendBuffer.Length; } @@ -262,10 +277,13 @@ await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Binary, /// /// A tuple containing the received text, 0-based substream index, and total bytes received. /// - protected async Task<(string text, byte streamIndex, int totalBytes)> ReceiveTextMultiplexed(WebSocket webSocket) + protected async Task<(string text, byte streamIndex, int totalBytes)> ReceiveTextMultiplexed( + WebSocket webSocket) { if (webSocket == null) + { throw new ArgumentNullException(nameof(webSocket)); + } byte[] receivedData; using (MemoryStream buffer = new MemoryStream()) @@ -273,7 +291,10 @@ await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Binary, byte[] receiveBuffer = new byte[1024]; WebSocketReceiveResult receiveResult = await webSocket.ReceiveAsync(receiveBuffer, TestCancellation); if (receiveResult.MessageType != WebSocketMessageType.Binary) - throw new IOException($"Received unexpected WebSocket message of type '{receiveResult.MessageType}'."); + { + throw new IOException( + $"Received unexpected WebSocket message of type '{receiveResult.MessageType}'."); + } buffer.Write(receiveBuffer, 0, receiveResult.Count); @@ -291,8 +312,7 @@ await webSocket.SendAsync(sendBuffer, WebSocketMessageType.Binary, return ( text: Encoding.ASCII.GetString(receivedData, 1, receivedData.Length - 1), streamIndex: receivedData[0], - totalBytes: receivedData.Length - ); + totalBytes: receivedData.Length); } public void Dispose() diff --git a/tests/KubernetesClient.Tests/YamlTests.cs b/tests/KubernetesClient.Tests/YamlTests.cs index d0072efbc..9a7a226ac 100644 --- a/tests/KubernetesClient.Tests/YamlTests.cs +++ b/tests/KubernetesClient.Tests/YamlTests.cs @@ -111,15 +111,7 @@ public void LoadFromStream() [Fact] public void WriteToString() { - var pod = new V1Pod() - { - ApiVersion = "v1", - Kind = "Pod", - Metadata = new V1ObjectMeta() - { - Name = "foo" - } - }; + var pod = new V1Pod() { ApiVersion = "v1", Kind = "Pod", Metadata = new V1ObjectMeta() { Name = "foo" } }; var yaml = Yaml.SaveToString(pod); Assert.True(ToLines(@"apiVersion: v1 @@ -135,11 +127,7 @@ public void WriteNamespacedToString() { ApiVersion = "v1", Kind = "Pod", - Metadata = new V1ObjectMeta() - { - Name = "foo", - NamespaceProperty = "bar" - } + Metadata = new V1ObjectMeta() { Name = "foo", NamespaceProperty = "bar" }, }; var yaml = Yaml.SaveToString(pod); @@ -157,11 +145,7 @@ public void WritePropertyNamedReadOnlyToString() { ApiVersion = "v1", Kind = "Pod", - Metadata = new V1ObjectMeta() - { - Name = "foo", - NamespaceProperty = "bar" - }, + Metadata = new V1ObjectMeta() { Name = "foo", NamespaceProperty = "bar" }, Spec = new V1PodSpec() { Containers = new[] @@ -173,20 +157,16 @@ public void WritePropertyNamedReadOnlyToString() { 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 }, } } } - } + }, }; var yaml = Yaml.SaveToString(pod); @@ -218,6 +198,7 @@ private static IEnumerable ToLines(string s) { yield break; } + yield return line; } } @@ -295,10 +276,7 @@ public void SerializeIntOrString() - port: 3000 targetPort: 3000"; - Dictionary labels = new Dictionary - { - {"app", "test"} - }; + Dictionary labels = new Dictionary { { "app", "test" } }; var obj = new V1Service { Kind = "Service", @@ -306,15 +284,8 @@ public void SerializeIntOrString() ApiVersion = "v1", Spec = new V1ServiceSpec { - Ports = new List - { - new V1ServicePort - { - Port = 3000, - TargetPort = 3000 - } - } - } + Ports = new List { new V1ServicePort { Port = 3000, TargetPort = 3000 } } + }, }; var output = Yaml.SaveToString(obj);