Add support for Azure AAD based authentication. (#193)
This commit is contained in:
24
src/KubernetesClient/KubeConfigModels/AuthProvider.cs
Normal file
24
src/KubernetesClient/KubeConfigModels/AuthProvider.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
namespace k8s.KubeConfigModels
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using YamlDotNet.RepresentationModel;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
|
||||||
|
/// </summary>
|
||||||
|
public class AuthProvider {
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the nickname for this auth provider.
|
||||||
|
/// </summary>
|
||||||
|
[YamlMember(Alias = "name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the configuration for this auth provider
|
||||||
|
/// </summary>
|
||||||
|
[YamlMember(Alias = "config")]
|
||||||
|
public Dictionary<string, string> Config { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,82 +3,82 @@ namespace k8s.KubeConfigModels
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using YamlDotNet.RepresentationModel;
|
using YamlDotNet.RepresentationModel;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
|
/// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class UserCredentials
|
public class UserCredentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets PEM-encoded data from a client cert file for TLS. Overrides <see cref="ClientCertificate"/>.
|
/// Gets or sets PEM-encoded data from a client cert file for TLS. Overrides <see cref="ClientCertificate"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "client-certificate-data", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "client-certificate-data", ApplyNamingConventions = false)]
|
||||||
public string ClientCertificateData { get; set; }
|
public string ClientCertificateData { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the path to a client cert file for TLS.
|
/// Gets or sets the path to a client cert file for TLS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "client-certificate", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "client-certificate", ApplyNamingConventions = false)]
|
||||||
public string ClientCertificate { get; set; }
|
public string ClientCertificate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets PEM-encoded data from a client key file for TLS. Overrides <see cref="ClientKey"/>.
|
/// Gets or sets PEM-encoded data from a client key file for TLS. Overrides <see cref="ClientKey"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "client-key-data", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "client-key-data", ApplyNamingConventions = false)]
|
||||||
public string ClientKeyData { get; set; }
|
public string ClientKeyData { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the path to a client key file for TLS.
|
/// Gets or sets the path to a client key file for TLS.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "client-key", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "client-key", ApplyNamingConventions = false)]
|
||||||
public string ClientKey { get; set; }
|
public string ClientKey { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the bearer token for authentication to the kubernetes cluster.
|
/// Gets or sets the bearer token for authentication to the kubernetes cluster.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "token")]
|
[YamlMember(Alias = "token")]
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the username to imperonate. The name matches the flag.
|
/// Gets or sets the username to imperonate. The name matches the flag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "as")]
|
[YamlMember(Alias = "as")]
|
||||||
public string Impersonate { get; set; }
|
public string Impersonate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the groups to imperonate.
|
/// Gets or sets the groups to imperonate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "as-groups", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "as-groups", ApplyNamingConventions = false)]
|
||||||
public IEnumerable<string> ImpersonateGroups { get; set; } = new string[0];
|
public IEnumerable<string> ImpersonateGroups { get; set; } = new string[0];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets additional information for impersonated user.
|
/// Gets or sets additional information for impersonated user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "as-user-extra", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "as-user-extra", ApplyNamingConventions = false)]
|
||||||
public Dictionary<string, string> ImpersonateUserExtra { get; set; } = new Dictionary<string, string>();
|
public Dictionary<string, string> ImpersonateUserExtra { get; set; } = new Dictionary<string, string>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the username for basic authentication to the kubernetes cluster.
|
/// Gets or sets the username for basic authentication to the kubernetes cluster.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "username")]
|
[YamlMember(Alias = "username")]
|
||||||
public string UserName { get; set; }
|
public string UserName { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the password for basic authentication to the kubernetes cluster.
|
/// Gets or sets the password for basic authentication to the kubernetes cluster.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "password")]
|
[YamlMember(Alias = "password")]
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets custom authentication plugin for the kubernetes cluster.
|
/// Gets or sets custom authentication plugin for the kubernetes cluster.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "auth-provider", ApplyNamingConventions = false)]
|
[YamlMember(Alias = "auth-provider", ApplyNamingConventions = false)]
|
||||||
public Dictionary<string, dynamic> AuthProvider { get; set; }
|
public AuthProvider AuthProvider { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields.
|
/// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[YamlMember(Alias = "extensions")]
|
[YamlMember(Alias = "extensions")]
|
||||||
public IDictionary<string, dynamic> Extensions { get; set; }
|
public IDictionary<string, dynamic> Extensions { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,8 @@ namespace k8s
|
|||||||
/// Initializes a new instance of the <see cref="KubernetesClientConfiguration" /> from config file
|
/// Initializes a new instance of the <see cref="KubernetesClientConfiguration" /> from config file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="masterUrl">kube api server endpoint</param>
|
/// <param name="masterUrl">kube api server endpoint</param>
|
||||||
/// <param name="kubeconfigPath">Explicit file path to kubeconfig. Set to null to use the default file path</param>
|
/// <param name="kubeconfigPath">Explicit file path to kubeconfig. Set to null to use the default file path</param>
|
||||||
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
||||||
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
||||||
public static KubernetesClientConfiguration BuildConfigFromConfigFile(string kubeconfigPath = null,
|
public static KubernetesClientConfiguration BuildConfigFromConfigFile(string kubeconfigPath = null,
|
||||||
string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
|
string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
|
||||||
@@ -42,8 +42,8 @@ namespace k8s
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="kubeconfig">Fileinfo of the kubeconfig, cannot be null</param>
|
/// <param name="kubeconfig">Fileinfo of the kubeconfig, cannot be null</param>
|
||||||
/// <param name="currentContext">override the context in config file, set null if do not want to override</param>
|
/// <param name="currentContext">override the context in config file, set null if do not want to override</param>
|
||||||
/// <param name="masterUrl">override the kube api server endpoint, set null if do not want to override</param>
|
/// <param name="masterUrl">override the kube api server endpoint, set null if do not want to override</param>
|
||||||
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
||||||
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
||||||
public static KubernetesClientConfiguration BuildConfigFromConfigFile(FileInfo kubeconfig,
|
public static KubernetesClientConfiguration BuildConfigFromConfigFile(FileInfo kubeconfig,
|
||||||
string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
|
string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
|
||||||
@@ -239,6 +239,27 @@ namespace k8s
|
|||||||
userCredentialsFound = true;
|
userCredentialsFound = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (userDetails.UserCredentials.AuthProvider != null) {
|
||||||
|
if (userDetails.UserCredentials.AuthProvider.Name == "azure" &&
|
||||||
|
userDetails.UserCredentials.AuthProvider.Config != null &&
|
||||||
|
userDetails.UserCredentials.AuthProvider.Config.ContainsKey("access-token")) {
|
||||||
|
var config = userDetails.UserCredentials.AuthProvider.Config;
|
||||||
|
if (config.ContainsKey("expires-on")) {
|
||||||
|
var expires = DateTimeOffset.FromUnixTimeSeconds(Int32.Parse(config["expires-on"]));
|
||||||
|
if (DateTimeOffset.Compare(expires, DateTimeOffset.Now) <= 0) {
|
||||||
|
var tenantId = config["tenant-id"];
|
||||||
|
var clientId = config["client-id"];
|
||||||
|
var apiServerId = config["apiserver-id"];
|
||||||
|
var refresh = config["refresh-token"];
|
||||||
|
var newToken = RenewAzureToken(tenantId, clientId, apiServerId, refresh);
|
||||||
|
config["access-token"] = newToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AccessToken = config["access-token"];
|
||||||
|
userCredentialsFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!userCredentialsFound)
|
if (!userCredentialsFound)
|
||||||
{
|
{
|
||||||
throw new KubeConfigException(
|
throw new KubeConfigException(
|
||||||
@@ -246,11 +267,15 @@ namespace k8s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string RenewAzureToken(string tenantId, string clientId, string apiServerId, string refresh) {
|
||||||
|
throw new KubeConfigException("Refresh not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads entire Kube Config from default or explicit file path
|
/// Loads entire Kube Config from default or explicit file path
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="kubeconfigPath">Explicit file path to kubeconfig. Set to null to use the default file path</param>
|
/// <param name="kubeconfigPath">Explicit file path to kubeconfig. Set to null to use the default file path</param>
|
||||||
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
||||||
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
||||||
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
||||||
public static async Task<K8SConfiguration> LoadKubeConfigAsync(string kubeconfigPath = null, bool useRelativePaths = true)
|
public static async Task<K8SConfiguration> LoadKubeConfigAsync(string kubeconfigPath = null, bool useRelativePaths = true)
|
||||||
@@ -263,8 +288,8 @@ namespace k8s
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads entire Kube Config from default or explicit file path
|
/// Loads entire Kube Config from default or explicit file path
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="kubeconfigPath">Explicit file path to kubeconfig. Set to null to use the default file path</param>
|
/// <param name="kubeconfigPath">Explicit file path to kubeconfig. Set to null to use the default file path</param>
|
||||||
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
||||||
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
||||||
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
||||||
public static K8SConfiguration LoadKubeConfig(string kubeconfigPath = null, bool useRelativePaths = true)
|
public static K8SConfiguration LoadKubeConfig(string kubeconfigPath = null, bool useRelativePaths = true)
|
||||||
@@ -275,8 +300,8 @@ namespace k8s
|
|||||||
// <summary>
|
// <summary>
|
||||||
/// Loads Kube Config
|
/// Loads Kube Config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="kubeconfig">Kube config file contents</param>
|
/// <param name="kubeconfig">Kube config file contents</param>
|
||||||
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
||||||
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
||||||
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
||||||
public static async Task<K8SConfiguration> LoadKubeConfigAsync(FileInfo kubeconfig, bool useRelativePaths = true)
|
public static async Task<K8SConfiguration> LoadKubeConfigAsync(FileInfo kubeconfig, bool useRelativePaths = true)
|
||||||
@@ -288,12 +313,12 @@ namespace k8s
|
|||||||
|
|
||||||
using (var stream = kubeconfig.OpenRead())
|
using (var stream = kubeconfig.OpenRead())
|
||||||
{
|
{
|
||||||
var config = await Yaml.LoadFromStreamAsync<K8SConfiguration>(stream);
|
var config = await Yaml.LoadFromStreamAsync<K8SConfiguration>(stream);
|
||||||
|
|
||||||
if (useRelativePaths)
|
if (useRelativePaths)
|
||||||
{
|
{
|
||||||
config.FileName = kubeconfig.FullName;
|
config.FileName = kubeconfig.FullName;
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@@ -302,8 +327,8 @@ namespace k8s
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads Kube Config
|
/// Loads Kube Config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="kubeconfig">Kube config file contents</param>
|
/// <param name="kubeconfig">Kube config file contents</param>
|
||||||
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
/// <param name="useRelativePaths">When <see langword="true"/>, the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
|
||||||
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
/// file is located. When <see langword="false"/>, the paths will be considered to be relative to the current working directory.</param>
|
||||||
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
/// <returns>Instance of the <see cref="K8SConfiguration"/> class</returns>
|
||||||
public static K8SConfiguration LoadKubeConfig(FileInfo kubeconfig, bool useRelativePaths = true)
|
public static K8SConfiguration LoadKubeConfig(FileInfo kubeconfig, bool useRelativePaths = true)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using k8s.Exceptions;
|
using k8s.Exceptions;
|
||||||
using k8s.KubeConfigModels;
|
using k8s.KubeConfigModels;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace k8s.Tests
|
namespace k8s.Tests
|
||||||
@@ -272,8 +272,8 @@ namespace k8s.Tests
|
|||||||
public void DeletedConfigurationFile()
|
public void DeletedConfigurationFile()
|
||||||
{
|
{
|
||||||
var assetFileInfo = new FileInfo("assets/kubeconfig.yml");
|
var assetFileInfo = new FileInfo("assets/kubeconfig.yml");
|
||||||
var tempFileInfo = new FileInfo(Path.GetTempFileName());
|
var tempFileInfo = new FileInfo(Path.GetTempFileName());
|
||||||
|
|
||||||
File.Copy(assetFileInfo.FullName, tempFileInfo.FullName, /* overwrite: */ true);
|
File.Copy(assetFileInfo.FullName, tempFileInfo.FullName, /* overwrite: */ true);
|
||||||
|
|
||||||
KubernetesClientConfiguration config;
|
KubernetesClientConfiguration config;
|
||||||
@@ -321,125 +321,125 @@ namespace k8s.Tests
|
|||||||
{
|
{
|
||||||
var filePath = "assets/kubeconfig.as-user-extra.yml";
|
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);
|
Assert.NotNull(cfg.Host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ensures Kube config file is loaded from explicit file
|
/// Ensures Kube config file is loaded from explicit file
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact]
|
[Fact]
|
||||||
public void LoadKubeConfigExplicitFilePath()
|
public void LoadKubeConfigExplicitFilePath()
|
||||||
{
|
{
|
||||||
var txt = File.ReadAllText("assets/kubeconfig.yml");
|
var txt = File.ReadAllText("assets/kubeconfig.yml");
|
||||||
var expectedCfg = Yaml.LoadFromString<K8SConfiguration>(txt);
|
var expectedCfg = Yaml.LoadFromString<K8SConfiguration>(txt);
|
||||||
|
|
||||||
var cfg = KubernetesClientConfiguration.LoadKubeConfig("assets/kubeconfig.yml");
|
var cfg = KubernetesClientConfiguration.LoadKubeConfig("assets/kubeconfig.yml");
|
||||||
|
|
||||||
Assert.NotNull(cfg);
|
Assert.NotNull(cfg);
|
||||||
AssertConfigEqual(expectedCfg, cfg);
|
AssertConfigEqual(expectedCfg, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void LoadKubeConfigFileInfo()
|
public void LoadKubeConfigFileInfo()
|
||||||
{
|
{
|
||||||
var filePath = "assets/kubeconfig.yml";
|
var filePath = "assets/kubeconfig.yml";
|
||||||
var txt = File.ReadAllText(filePath);
|
var txt = File.ReadAllText(filePath);
|
||||||
var expectedCfg = Yaml.LoadFromString<K8SConfiguration>(txt);
|
var expectedCfg = Yaml.LoadFromString<K8SConfiguration>(txt);
|
||||||
|
|
||||||
var fileInfo = new FileInfo(filePath);
|
var fileInfo = new FileInfo(filePath);
|
||||||
var cfg = KubernetesClientConfiguration.LoadKubeConfig(fileInfo);
|
var cfg = KubernetesClientConfiguration.LoadKubeConfig(fileInfo);
|
||||||
|
|
||||||
Assert.NotNull(cfg);
|
Assert.NotNull(cfg);
|
||||||
AssertConfigEqual(expectedCfg, cfg);
|
AssertConfigEqual(expectedCfg, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void LoadKubeConfigStream()
|
public void LoadKubeConfigStream()
|
||||||
{
|
{
|
||||||
var filePath = "assets/kubeconfig.yml";
|
var filePath = "assets/kubeconfig.yml";
|
||||||
var txt = File.ReadAllText(filePath);
|
var txt = File.ReadAllText(filePath);
|
||||||
var expectedCfg = Yaml.LoadFromString<K8SConfiguration>(txt);
|
var expectedCfg = Yaml.LoadFromString<K8SConfiguration>(txt);
|
||||||
|
|
||||||
var fileInfo = new FileInfo(filePath);
|
var fileInfo = new FileInfo(filePath);
|
||||||
K8SConfiguration cfg;
|
K8SConfiguration cfg;
|
||||||
using (var stream = fileInfo.OpenRead())
|
using (var stream = fileInfo.OpenRead())
|
||||||
{
|
{
|
||||||
cfg = KubernetesClientConfiguration.LoadKubeConfig(stream);
|
cfg = KubernetesClientConfiguration.LoadKubeConfig(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.NotNull(cfg);
|
Assert.NotNull(cfg);
|
||||||
AssertConfigEqual(expectedCfg, cfg);
|
AssertConfigEqual(expectedCfg, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertConfigEqual(K8SConfiguration expected, K8SConfiguration actual)
|
private void AssertConfigEqual(K8SConfiguration expected, K8SConfiguration actual)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected.ApiVersion, actual.ApiVersion);
|
Assert.Equal(expected.ApiVersion, actual.ApiVersion);
|
||||||
Assert.Equal(expected.CurrentContext, actual.CurrentContext);
|
Assert.Equal(expected.CurrentContext, actual.CurrentContext);
|
||||||
|
|
||||||
foreach (var expectedContext in expected.Contexts)
|
foreach (var expectedContext in expected.Contexts)
|
||||||
{
|
{
|
||||||
// Will throw exception if not found
|
// Will throw exception if not found
|
||||||
var actualContext = actual.Contexts.First(c => c.Name.Equals(expectedContext.Name));
|
var actualContext = actual.Contexts.First(c => c.Name.Equals(expectedContext.Name));
|
||||||
AssertContextEqual(expectedContext, actualContext);
|
AssertContextEqual(expectedContext, actualContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var expectedCluster in expected.Clusters)
|
foreach (var expectedCluster in expected.Clusters)
|
||||||
{
|
{
|
||||||
// Will throw exception if not found
|
// Will throw exception if not found
|
||||||
var actualCluster = actual.Clusters.First(c => c.Name.Equals(expectedCluster.Name));
|
var actualCluster = actual.Clusters.First(c => c.Name.Equals(expectedCluster.Name));
|
||||||
AssertClusterEqual(expectedCluster, actualCluster);
|
AssertClusterEqual(expectedCluster, actualCluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var expectedUser in expected.Users)
|
foreach (var expectedUser in expected.Users)
|
||||||
{
|
{
|
||||||
// Will throw exception if not found
|
// Will throw exception if not found
|
||||||
var actualUser = actual.Users.First(u => u.Name.Equals(expectedUser.Name));
|
var actualUser = actual.Users.First(u => u.Name.Equals(expectedUser.Name));
|
||||||
AssertUserEqual(expectedUser, actualUser);
|
AssertUserEqual(expectedUser, actualUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertContextEqual(Context expected, Context actual)
|
private void AssertContextEqual(Context expected, Context actual)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected.Name, actual.Name);
|
Assert.Equal(expected.Name, actual.Name);
|
||||||
Assert.Equal(expected.Namespace, actual.Namespace);
|
Assert.Equal(expected.Namespace, actual.Namespace);
|
||||||
Assert.Equal(expected.ContextDetails.Cluster, actual.ContextDetails.Cluster);
|
Assert.Equal(expected.ContextDetails.Cluster, actual.ContextDetails.Cluster);
|
||||||
Assert.Equal(expected.ContextDetails.User, actual.ContextDetails.User);
|
Assert.Equal(expected.ContextDetails.User, actual.ContextDetails.User);
|
||||||
Assert.Equal(expected.ContextDetails.Namespace, actual.ContextDetails.Namespace);
|
Assert.Equal(expected.ContextDetails.Namespace, actual.ContextDetails.Namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertClusterEqual(Cluster expected, Cluster actual)
|
private void AssertClusterEqual(Cluster expected, Cluster actual)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected.Name, actual.Name);
|
Assert.Equal(expected.Name, actual.Name);
|
||||||
Assert.Equal(expected.ClusterEndpoint.CertificateAuthority, actual.ClusterEndpoint.CertificateAuthority);
|
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.Server, actual.ClusterEndpoint.Server);
|
||||||
Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify);
|
Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AssertUserEqual(User expected, User actual)
|
private void AssertUserEqual(User expected, User actual)
|
||||||
{
|
{
|
||||||
Assert.Equal(expected.Name, actual.Name);
|
Assert.Equal(expected.Name, actual.Name);
|
||||||
|
|
||||||
var expectedCreds = expected.UserCredentials;
|
var expectedCreds = expected.UserCredentials;
|
||||||
var actualCreds = actual.UserCredentials;
|
var actualCreds = actual.UserCredentials;
|
||||||
|
|
||||||
Assert.Equal(expectedCreds.ClientCertificateData, actualCreds.ClientCertificateData);
|
Assert.Equal(expectedCreds.ClientCertificateData, actualCreds.ClientCertificateData);
|
||||||
Assert.Equal(expectedCreds.ClientCertificate, actualCreds.ClientCertificate);
|
Assert.Equal(expectedCreds.ClientCertificate, actualCreds.ClientCertificate);
|
||||||
Assert.Equal(expectedCreds.ClientKeyData, actualCreds.ClientKeyData);
|
Assert.Equal(expectedCreds.ClientKeyData, actualCreds.ClientKeyData);
|
||||||
Assert.Equal(expectedCreds.ClientKey, actualCreds.ClientKey);
|
Assert.Equal(expectedCreds.ClientKey, actualCreds.ClientKey);
|
||||||
Assert.Equal(expectedCreds.Token, actualCreds.Token);
|
Assert.Equal(expectedCreds.Token, actualCreds.Token);
|
||||||
Assert.Equal(expectedCreds.Impersonate, actualCreds.Impersonate);
|
Assert.Equal(expectedCreds.Impersonate, actualCreds.Impersonate);
|
||||||
Assert.Equal(expectedCreds.UserName, actualCreds.UserName);
|
Assert.Equal(expectedCreds.UserName, actualCreds.UserName);
|
||||||
Assert.Equal(expectedCreds.Password, actualCreds.Password);
|
Assert.Equal(expectedCreds.Password, actualCreds.Password);
|
||||||
|
|
||||||
Assert.True(expectedCreds.ImpersonateGroups.All(x => actualCreds.ImpersonateGroups.Contains(x)));
|
Assert.True(expectedCreds.ImpersonateGroups.All(x => actualCreds.ImpersonateGroups.Contains(x)));
|
||||||
Assert.True(expectedCreds.ImpersonateUserExtra.All(x => actualCreds.ImpersonateUserExtra.Contains(x)));
|
Assert.True(expectedCreds.ImpersonateUserExtra.All(x => actualCreds.ImpersonateUserExtra.Contains(x)));
|
||||||
|
|
||||||
if (expectedCreds.AuthProvider != null)
|
if (expectedCreds.AuthProvider != null)
|
||||||
{
|
{
|
||||||
Assert.True(expectedCreds.AuthProvider.All(x => actualCreds.AuthProvider.Contains(x)));
|
Assert.True(expectedCreds.AuthProvider.Config.All(x => actualCreds.AuthProvider.Config.Contains(x)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user