Fix kubeconfig extension handling (#556)

Extensions on kubeconfig files are stored as a list of NamedExtension objects, not a dictionary.
This commit is contained in:
Frederik Carlier
2021-01-27 08:57:40 -08:00
committed by GitHub
parent 46d4eaa7d8
commit 6f5706d753
10 changed files with 82 additions and 20 deletions

View File

@@ -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.
/// </summary>
[YamlMember(Alias = "extensions")]
public IDictionary<string, dynamic> Extensions { get; set; }
public IEnumerable<NamedExtension> Extensions { get; set; }
}
}

View File

@@ -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; }
/// <summary>
/// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields.
/// </summary>
[YamlMember(Alias = "extensions")]
public IEnumerable<NamedExtension> 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; }

View File

@@ -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.
/// </summary>
[YamlMember(Alias = "extensions")]
public IDictionary<string, dynamic> Extensions { get; set; }
public IEnumerable<NamedExtension> Extensions { get; set; }
}
}

View File

@@ -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.
/// </summary>
[YamlMember(Alias = "extensions")]
public IDictionary<string, dynamic> Extensions { get; set; }
public IEnumerable<NamedExtension> Extensions { get; set; }
/// <summary>
/// Gets or sets the name of the Kubernetes configuration file. This property is set only when the configuration

View File

@@ -0,0 +1,22 @@
using YamlDotNet.Serialization;
namespace k8s.KubeConfigModels
{
/// <summary>
/// <see cref="NamedExtension"/> relates nicknames to extension information
/// </summary>
public class NamedExtension
{
/// <summary>
/// Gets or sets the nickname for this extension.
/// </summary>
[YamlMember(Alias = "name")]
public string Name { get; set; }
/// <summary>
/// Get or sets the extension information.
/// </summary>
[YamlMember(Alias = "extension")]
public dynamic Extension { get; set; }
}
}

View File

@@ -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.
/// </summary>
[YamlMember(Alias = "extensions")]
public IDictionary<string, dynamic> Extensions { get; set; }
public IEnumerable<NamedExtension> Extensions { get; set; }
/// <summary>
/// Gets or sets external command and its arguments to receive user credentials

View File

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

View File

@@ -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);
}
/// <summary>
/// Ensures Kube config file is loaded from explicit file
/// </summary>
@@ -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);
}
/// <summary>

View File

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

View File

@@ -3,4 +3,6 @@ kind: Config
preferences:
colors: true
extensions:
- name: foo
extension:
foo: bar