diff --git a/src/KubeConfigModels/K8SConfiguration.cs b/src/KubeConfigModels/K8SConfiguration.cs index 723b360..7d6184f 100644 --- a/src/KubeConfigModels/K8SConfiguration.cs +++ b/src/KubeConfigModels/K8SConfiguration.cs @@ -1,4 +1,4 @@ -namespace k8s.KubeConfigModels +namespace k8s.KubeConfigModels { using System.Collections.Generic; using YamlDotNet.Serialization; @@ -9,7 +9,7 @@ public class K8SConfiguration { [YamlMember(Alias = "preferences")] - public IDictionary preferences{ get; set; } + public IDictionary Preferences{ get; set; } [YamlMember(Alias = "apiVersion")] public string ApiVersion { get; set; } @@ -21,12 +21,12 @@ public string CurrentContext { get; set; } [YamlMember(Alias = "contexts")] - public IEnumerable Contexts { get; set; } + public IEnumerable Contexts { get; set; } = new Context[0]; [YamlMember(Alias = "clusters")] - public IEnumerable Clusters { get; set; } + public IEnumerable Clusters { get; set; } = new Cluster[0]; [YamlMember(Alias = "users")] - public IEnumerable Users { get; set; } + public IEnumerable Users { get; set; } = new User[0]; } } diff --git a/src/Kubernetes.ConfigInit.cs b/src/Kubernetes.ConfigInit.cs index cb01062..a95a6e3 100644 --- a/src/Kubernetes.ConfigInit.cs +++ b/src/Kubernetes.ConfigInit.cs @@ -1,10 +1,10 @@ -using k8s.Models; using System; using System.Diagnostics.CodeAnalysis; using System.Net.Http; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using k8s.Exceptions; +using k8s.Models; using Microsoft.Rest; namespace k8s @@ -22,8 +22,21 @@ namespace k8s /// public Kubernetes(KubernetesClientConfiguration config, params DelegatingHandler[] handlers) : this(handlers) { + if (string.IsNullOrWhiteSpace(config.Host)) + { + throw new KubeConfigException("Host url must be set"); + } + + try + { + BaseUri = new Uri(config.Host); + } + catch (UriFormatException e) + { + throw new KubeConfigException("Bad host url", e); + } + CaCert = config.SslCaCert; - BaseUri = new Uri(config.Host); if (BaseUri.Scheme == "https") { diff --git a/src/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClientConfiguration.ConfigFile.cs index 8024764..6ec531f 100644 --- a/src/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClientConfiguration.ConfigFile.cs @@ -12,12 +12,7 @@ namespace k8s public partial class KubernetesClientConfiguration { /// - /// Gets CurrentContext - /// - public string CurrentContext { get; private set; } - - /// - /// kubeconfig Default Location + /// kubeconfig Default Location /// private static readonly string KubeConfigDefaultLocation = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) @@ -25,22 +20,29 @@ namespace k8s : Path.Combine(Environment.GetEnvironmentVariable("HOME"), ".kube/config"); /// - /// Initializes a new instance of the from config file + /// Gets CurrentContext + /// + public string CurrentContext { get; private set; } + + /// + /// Initializes a new instance of the from config file /// /// kube api server endpoint /// kubeconfig filepath - public static KubernetesClientConfiguration BuildConfigFromConfigFile(string masterUrl = null, string kubeconfigPath = null) + public static KubernetesClientConfiguration BuildConfigFromConfigFile(string masterUrl = null, + string kubeconfigPath = null) { - return BuildConfigFromConfigFile(new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation), null, masterUrl); + return BuildConfigFromConfigFile(new FileInfo(kubeconfigPath ?? KubeConfigDefaultLocation), null, + masterUrl); } /// - /// /// /// Fileinfo of the kubeconfig, cannot be null /// override the context in config file, set null if do not want to override /// overrider kube api server endpoint, set null if do not want to override - public static KubernetesClientConfiguration BuildConfigFromConfigFile(FileInfo kubeconfig, string currentContext = null, string masterUrl = null) + public static KubernetesClientConfiguration BuildConfigFromConfigFile(FileInfo kubeconfig, + string currentContext = null, string masterUrl = null) { if (kubeconfig == null) { @@ -57,33 +59,18 @@ namespace k8s } return k8SConfiguration; } - /// - /// Validates and Intializes Client Configuration + /// Validates and Intializes Client Configuration /// /// Kubernetes Configuration /// Current Context private void Initialize(K8SConfiguration k8SConfig, string currentContext = null) { - if (k8SConfig.Contexts == null) - { - throw new KubeConfigException("No contexts found in kubeconfig"); - } - - if (k8SConfig.Clusters == null) - { - throw new KubeConfigException($"No clusters found in kubeconfig"); - } - - if (k8SConfig.Users == null) - { - throw new KubeConfigException($"No users found in kubeconfig"); - } - // current context currentContext = currentContext ?? k8SConfig.CurrentContext; - Context activeContext = + + var activeContext = k8SConfig.Contexts.FirstOrDefault( c => c.Name.Equals(currentContext, StringComparison.OrdinalIgnoreCase)); if (activeContext == null) @@ -91,12 +78,21 @@ namespace k8s throw new KubeConfigException($"CurrentContext: {currentContext} not found in contexts in kubeconfig"); } - this.CurrentContext = activeContext.Name; + CurrentContext = activeContext.Name; // cluster + SetClusterDetails(k8SConfig, activeContext); + + // user + SetUserDetails(k8SConfig, activeContext); + } + + private void SetClusterDetails(K8SConfiguration k8SConfig, Context activeContext) + { var clusterDetails = k8SConfig.Clusters.FirstOrDefault(c => c.Name.Equals(activeContext.ContextDetails.Cluster, StringComparison.OrdinalIgnoreCase)); + if (clusterDetails?.ClusterEndpoint == null) { throw new KubeConfigException($"Cluster not found for context {activeContext} in kubeconfig"); @@ -106,33 +102,49 @@ namespace k8s { throw new KubeConfigException($"Server not found for current-context {activeContext} in kubeconfig"); } + Host = clusterDetails.ClusterEndpoint.Server; - if (!clusterDetails.ClusterEndpoint.SkipTlsVerify && - string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthorityData) && - string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthority)) - { - throw new KubeConfigException( - $"neither certificate-authority-data nor certificate-authority not found for current-context :{activeContext} in kubeconfig"); - } + SkipTlsVerify = clusterDetails.ClusterEndpoint.SkipTlsVerify; - this.Host = clusterDetails.ClusterEndpoint.Server; - if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) + try { - string data = clusterDetails.ClusterEndpoint.CertificateAuthorityData; - this.SslCaCert = new X509Certificate2(Convert.FromBase64String(data)); - } - else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) - { - this.SslCaCert = new X509Certificate2(clusterDetails.ClusterEndpoint.CertificateAuthority); - } - this.SkipTlsVerify = clusterDetails.ClusterEndpoint.SkipTlsVerify; + var uri = new Uri(Host); + if (uri.Scheme == "https") + { + + // check certificate for https + if (!clusterDetails.ClusterEndpoint.SkipTlsVerify && + string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthorityData) && + string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthority)) + { + throw new KubeConfigException( + $"neither certificate-authority-data nor certificate-authority not found for current-context :{activeContext} in kubeconfig"); + } - // user - this.SetUserDetails(k8SConfig, activeContext); + if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) + { + var data = clusterDetails.ClusterEndpoint.CertificateAuthorityData; + SslCaCert = new X509Certificate2(Convert.FromBase64String(data)); + } + else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) + { + SslCaCert = new X509Certificate2(clusterDetails.ClusterEndpoint.CertificateAuthority); + } + } + } + catch (UriFormatException e) + { + throw new KubeConfigException("Bad Server host url", e); + } } private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) { + if (string.IsNullOrWhiteSpace(activeContext.ContextDetails.User)) + { + return; + } + var userDetails = k8SConfig.Users.FirstOrDefault(c => c.Name.Equals(activeContext.ContextDetails.User, StringComparison.OrdinalIgnoreCase)); @@ -151,14 +163,14 @@ namespace k8s // Basic and bearer tokens are mutually exclusive if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.Token)) { - this.AccessToken = userDetails.UserCredentials.Token; + AccessToken = userDetails.UserCredentials.Token; userCredentialsFound = true; } else if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.UserName) && !string.IsNullOrWhiteSpace(userDetails.UserCredentials.Password)) { - this.Username = userDetails.UserCredentials.UserName; - this.Password = userDetails.UserCredentials.Password; + Username = userDetails.UserCredentials.UserName; + Password = userDetails.UserCredentials.Password; userCredentialsFound = true; } @@ -166,16 +178,16 @@ namespace k8s if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientCertificateData) && !string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientKeyData)) { - this.ClientCertificateData = userDetails.UserCredentials.ClientCertificateData; - this.ClientCertificateKeyData = userDetails.UserCredentials.ClientKeyData; + ClientCertificateData = userDetails.UserCredentials.ClientCertificateData; + ClientCertificateKeyData = userDetails.UserCredentials.ClientKeyData; userCredentialsFound = true; } if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientCertificate) && !string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientKey)) { - this.ClientCertificateFilePath = userDetails.UserCredentials.ClientCertificate; - this.ClientKeyFilePath = userDetails.UserCredentials.ClientKey; + ClientCertificateFilePath = userDetails.UserCredentials.ClientCertificate; + ClientKeyFilePath = userDetails.UserCredentials.ClientKey; userCredentialsFound = true; } @@ -187,7 +199,7 @@ namespace k8s } /// - /// Loads Kube Config + /// Loads Kube Config /// /// Kube config file contents /// Instance of the class @@ -197,11 +209,10 @@ namespace k8s { throw new KubeConfigException($"kubeconfig file not found at {kubeconfig.FullName}"); } - var kubeconfigContent = File.ReadAllText(kubeconfig.FullName); var deserializeBuilder = new DeserializerBuilder(); var deserializer = deserializeBuilder.Build(); - return deserializer.Deserialize(kubeconfigContent); + return deserializer.Deserialize(kubeconfig.OpenText()); } } -} +}