diff --git a/src/KubernetesClient/KubeConfigModels/ClusterEndpoint.cs b/src/KubernetesClient/KubeConfigModels/ClusterEndpoint.cs index c86034a..af8913c 100644 --- a/src/KubernetesClient/KubeConfigModels/ClusterEndpoint.cs +++ b/src/KubernetesClient/KubeConfigModels/ClusterEndpoint.cs @@ -37,6 +37,6 @@ namespace k8s.KubeConfigModels /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields. /// [YamlMember(Alias = "extensions")] - public IDictionary Extensions { get; set; } + public IEnumerable Extensions { get; set; } } } diff --git a/src/KubernetesClient/KubeConfigModels/Context.cs b/src/KubernetesClient/KubeConfigModels/Context.cs index 739b6dd..1eeec04 100644 --- a/src/KubernetesClient/KubeConfigModels/Context.cs +++ b/src/KubernetesClient/KubeConfigModels/Context.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using YamlDotNet.Serialization; namespace k8s.KubeConfigModels @@ -20,6 +21,13 @@ namespace k8s.KubeConfigModels [YamlMember(Alias = "name")] public string Name { get; set; } + /// + /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields. + /// + [YamlMember(Alias = "extensions")] + public IEnumerable Extensions { get; set; } + + [Obsolete("This property is not set by the YAML config. Use ContextDetails.Namespace instead.")] [YamlMember(Alias = "namespace")] public string Namespace { get; set; } diff --git a/src/KubernetesClient/KubeConfigModels/ContextDetails.cs b/src/KubernetesClient/KubeConfigModels/ContextDetails.cs index 1fc5bfa..4a3db76 100644 --- a/src/KubernetesClient/KubeConfigModels/ContextDetails.cs +++ b/src/KubernetesClient/KubeConfigModels/ContextDetails.cs @@ -31,6 +31,6 @@ namespace k8s.KubeConfigModels /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields. /// [YamlMember(Alias = "extensions")] - public IDictionary Extensions { get; set; } + public IEnumerable Extensions { get; set; } } } diff --git a/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs b/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs index 2f66759..f4eb712 100644 --- a/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs +++ b/src/KubernetesClient/KubeConfigModels/K8SConfiguration.cs @@ -53,7 +53,7 @@ namespace k8s.KubeConfigModels /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields. /// [YamlMember(Alias = "extensions")] - public IDictionary Extensions { get; set; } + public IEnumerable Extensions { get; set; } /// /// Gets or sets the name of the Kubernetes configuration file. This property is set only when the configuration diff --git a/src/KubernetesClient/KubeConfigModels/NamedExtension.cs b/src/KubernetesClient/KubeConfigModels/NamedExtension.cs new file mode 100644 index 0000000..6761979 --- /dev/null +++ b/src/KubernetesClient/KubeConfigModels/NamedExtension.cs @@ -0,0 +1,22 @@ +using YamlDotNet.Serialization; + +namespace k8s.KubeConfigModels +{ + /// + /// relates nicknames to extension information + /// + public class NamedExtension + { + /// + /// Gets or sets the nickname for this extension. + /// + [YamlMember(Alias = "name")] + public string Name { get; set; } + + /// + /// Get or sets the extension information. + /// + [YamlMember(Alias = "extension")] + public dynamic Extension { get; set; } + } +} diff --git a/src/KubernetesClient/KubeConfigModels/UserCredentials.cs b/src/KubernetesClient/KubeConfigModels/UserCredentials.cs index ea91dff..c48b979 100644 --- a/src/KubernetesClient/KubeConfigModels/UserCredentials.cs +++ b/src/KubernetesClient/KubeConfigModels/UserCredentials.cs @@ -78,7 +78,7 @@ namespace k8s.KubeConfigModels /// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields. /// [YamlMember(Alias = "extensions")] - public IDictionary Extensions { get; set; } + public IEnumerable Extensions { get; set; } /// /// Gets or sets external command and its arguments to receive user credentials diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs index 06b983a..a703dad 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs @@ -773,19 +773,9 @@ namespace k8s } } - if (mergek8SConfig.Extensions != null) - { - foreach (var extension in mergek8SConfig.Extensions) - { - if (basek8SConfig.Extensions?.ContainsKey(extension.Key) == false) - { - basek8SConfig.Extensions[extension.Key] = extension.Value; - } - } - } - // Note, Clusters, Contexts, and Extensions are map-like in config despite being represented as a list here: // https://github.com/kubernetes/client-go/blob/ede92e0fe62deed512d9ceb8bf4186db9f3776ff/tools/clientcmd/api/types.go#L238 + basek8SConfig.Extensions = MergeLists(basek8SConfig.Extensions, mergek8SConfig.Extensions, (s) => s.Name); basek8SConfig.Clusters = MergeLists(basek8SConfig.Clusters, mergek8SConfig.Clusters, (s) => s.Name); basek8SConfig.Users = MergeLists(basek8SConfig.Users, mergek8SConfig.Users, (s) => s.Name); basek8SConfig.Contexts = MergeLists(basek8SConfig.Contexts, mergek8SConfig.Contexts, (s) => s.Name); diff --git a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs old mode 100755 new mode 100644 index 4c9108a..5ee560c --- a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs +++ b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs @@ -1,10 +1,11 @@ +using k8s.Exceptions; +using k8s.KubeConfigModels; using System; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading; -using k8s.Exceptions; -using k8s.KubeConfigModels; +using System.Threading.Tasks; using Xunit; namespace k8s.Tests @@ -372,6 +373,14 @@ namespace k8s.Tests Assert.NotNull(cfg.Host); } + [Fact] + public async Task ContextWithClusterExtensions() + { + var path = Path.GetFullPath("assets/kubeconfig.cluster-extensions.yml"); + + var cfg = await KubernetesClientConfiguration.BuildConfigFromConfigFileAsync(new FileInfo(path)).ConfigureAwait(false); + } + /// /// Ensures Kube config file is loaded from explicit file /// @@ -525,8 +534,8 @@ namespace k8s.Tests new FileInfo(path), new FileInfo(path), }); - Assert.Equal(1, cfg.Extensions.Count); - Assert.Equal(1, cfg.Preferences.Count); + Assert.Single(cfg.Extensions); + Assert.Single(cfg.Preferences); } /// diff --git a/tests/KubernetesClient.Tests/assets/kubeconfig.cluster-extensions.yml b/tests/KubernetesClient.Tests/assets/kubeconfig.cluster-extensions.yml new file mode 100644 index 0000000..b78717d --- /dev/null +++ b/tests/KubernetesClient.Tests/assets/kubeconfig.cluster-extensions.yml @@ -0,0 +1,31 @@ +apiVersion: v1 +clusters: +- cluster: + extensions: + - extension: + last-update: Wed, 27 Jan 2021 11:44:41 UTC + provider: minikube.sigs.k8s.io + version: v1.17.0 + name: cluster_info + server: https://192.168.49.2:8443 + name: minikube +contexts: +- context: + cluster: minikube + extensions: + - extension: + last-update: Wed, 27 Jan 2021 11:44:41 UTC + provider: minikube.sigs.k8s.io + version: v1.17.0 + name: context_info + namespace: default + user: minikube + name: minikube +current-context: minikube +kind: Config +preferences: {} +users: +- name: minikube + user: + password: secret + username: admin diff --git a/tests/KubernetesClient.Tests/assets/kubeconfig.preferences-extensions.yml b/tests/KubernetesClient.Tests/assets/kubeconfig.preferences-extensions.yml index 7e8a6d2..9099fe8 100644 --- a/tests/KubernetesClient.Tests/assets/kubeconfig.preferences-extensions.yml +++ b/tests/KubernetesClient.Tests/assets/kubeconfig.preferences-extensions.yml @@ -3,4 +3,6 @@ kind: Config preferences: colors: true extensions: - foo: bar + - name: foo + extension: + foo: bar