diff --git a/README.md b/README.md index e148315..5e229f1 100644 --- a/README.md +++ b/README.md @@ -1,43 +1,58 @@ # csharp Work In Progress -Currently only supported on Linux [![Travis](https://img.shields.io/travis/kubernetes-client/csharp.svg)](https://travis-ci.org/kubernetes-client/csharp) -# Generating the client code +# Generating the Client Code ## Prerequisites Check out the generator project into some other directory (henceforth `$GEN_DIR`) -``` +```bash cd $GEN_DIR/.. git clone https://github.com/kubernetes-client/gen ``` Install the [`autorest` tool](https://github.com/azure/autorest): -``` +```bash npm install autorest ``` ## Generating code -``` +```bash # Where REPO_DIR points to the root of the csharp repository cd ${REPO_DIR}/csharp/src ${GEN_DIR}/openapi/csharp.sh generated csharp.settings ``` -# Testing +# Usage + +## Prerequisities + +* [OpenSSL](https://www.openssl.org/) +* For Linux/Mac: + * LibCurl built with OpenSSL (Mac: `brew install curl --with-nghttp2`) + +## Running the Examples + +```bash +git clone git@github.com:kubernetes-client/csharp.git +cd csharp\examples\simple +dotnet run +``` + +## Testing The project uses [XUnit](https://xunit.github.io) as unit testing framework. -To run the tests you need to: +To run the tests ```bash -cd tests +cd csharp\tests dotnet restore dotnet xunit ``` \ No newline at end of file diff --git a/src/Kubernetes.Auth.cs b/src/Kubernetes.Auth.cs index 7ea4fcd..02767a4 100644 --- a/src/Kubernetes.Auth.cs +++ b/src/Kubernetes.Auth.cs @@ -71,10 +71,6 @@ !string.IsNullOrWhiteSpace(config.ClientKey))) { var pfxFilePath = await Utils.GeneratePfxAsync(config).ConfigureAwait(false); - if (string.IsNullOrWhiteSpace(pfxFilePath)) - { - throw new KubernetesClientException("Failed to generate pfx file"); - } var cert = new X509Certificate2(pfxFilePath, string.Empty, X509KeyStorageFlags.PersistKeySet); handler.ClientCertificates.Add(cert); diff --git a/src/KubernetesClientConfiguration.cs b/src/KubernetesClientConfiguration.cs index 71fcb42..916504e 100644 --- a/src/KubernetesClientConfiguration.cs +++ b/src/KubernetesClientConfiguration.cs @@ -16,17 +16,12 @@ namespace k8s { /// /// Initializes a new instance of the class. - /// Initializes a new instance of the ClientConfiguration class /// /// kubeconfig file info /// Context to use from kube config public KubernetesClientConfiguration(FileInfo kubeconfig = null, string currentContext = null) { - if (kubeconfig == null) - { - kubeconfig = new FileInfo(KubeConfigDefaultLocation); - } - var k8SConfig = this.LoadKubeConfig(kubeconfig); + var k8SConfig = this.LoadKubeConfig(kubeconfig ?? new FileInfo(KubeConfigDefaultLocation)); this.Initialize(k8SConfig, currentContext); } @@ -108,86 +103,73 @@ namespace k8s /// Current Context private void Initialize(K8SConfiguration k8SConfig, string currentContext = null) { - Context activeContext; - if (k8SConfig.Contexts == null) { throw new KubeConfigException("No contexts found in kubeconfig"); - } - - // set the currentCOntext to passed context if not null - if (!string.IsNullOrWhiteSpace(currentContext)) - { - - activeContext = k8SConfig.Contexts.FirstOrDefault(c => c.Name.Equals(currentContext, StringComparison.OrdinalIgnoreCase)); - if (activeContext != null) - { - this.CurrentContext = activeContext.Name; - } - else - { - throw new KubeConfigException($"CurrentContext: {0} not found in contexts in kubeconfig"); - } - } - // otherwise set current context from kubeconfig - else - { - activeContext = k8SConfig.Contexts.FirstOrDefault(c => c.Name.Equals(k8SConfig.CurrentContext, StringComparison.OrdinalIgnoreCase)); - - if (activeContext == null) - { - throw new KubeConfigException($"CurrentContext: {currentContext} not found in contexts in kubeconfig"); - } - - this.CurrentContext = activeContext.Name; } if (k8SConfig.Clusters == null) { - throw new KubeConfigException($"clusters not found for current-context :{activeContext} in kubeconfig"); + throw new KubeConfigException($"No clusters found in kubeconfig"); } - - var clusterDetails = k8SConfig.Clusters.FirstOrDefault(c => c.Name.Equals(activeContext.ContextDetails.Cluster, StringComparison.OrdinalIgnoreCase)); - if (clusterDetails?.ClusterEndpoint != null) + + if (k8SConfig.Users == null) { - if (string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.Server)) - { - throw new KubeConfigException($"server not found for current-context :{activeContext} in kubeconfig"); - } - - 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"); - } - - this.Host = clusterDetails.ClusterEndpoint.Server; - if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) { - string data = clusterDetails.ClusterEndpoint.CertificateAuthorityData; - this.SslCaCert = new X509Certificate2(System.Text.Encoding.UTF8.GetBytes(Utils.Base64Decode(data))); - } - else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) { - this.SslCaCert = new X509Certificate2(clusterDetails.ClusterEndpoint.CertificateAuthority, null); - } - this.SkipTlsVerify = clusterDetails.ClusterEndpoint.SkipTlsVerify; + throw new KubeConfigException($"No users found in kubeconfig"); } - else + + // current context + currentContext = currentContext ?? k8SConfig.CurrentContext; + Context activeContext = k8SConfig.Contexts.FirstOrDefault(c => c.Name.Equals(currentContext, StringComparison.OrdinalIgnoreCase)); + if (activeContext == null) { - throw new KubeConfigException($"Cluster details not found for current-context: {activeContext} in kubeconfig"); + throw new KubeConfigException($"CurrentContext: {currentContext} not found in contexts in kubeconfig"); } - // set user details from kubeconfig - var userDetails = k8SConfig.Users.FirstOrDefault(c => c.Name.Equals(activeContext.ContextDetails.User, StringComparison.OrdinalIgnoreCase)); + this.CurrentContext = activeContext.Name; - this.SetUserDetails(userDetails); + // cluster + 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"); + } + + if (string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.Server)) + { + throw new KubeConfigException($"Server not found for current-context {activeContext} in kubeconfig"); + } + + 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"); + } + + this.Host = clusterDetails.ClusterEndpoint.Server; + if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) + { + string data = clusterDetails.ClusterEndpoint.CertificateAuthorityData; + this.SslCaCert = new X509Certificate2(System.Text.Encoding.UTF8.GetBytes(Utils.Base64Decode(data))); + } + else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) + { + this.SslCaCert = new X509Certificate2(clusterDetails.ClusterEndpoint.CertificateAuthority, null); + } + this.SkipTlsVerify = clusterDetails.ClusterEndpoint.SkipTlsVerify; + + // user + this.SetUserDetails(k8SConfig, activeContext); } - private void SetUserDetails(User userDetails) + private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) { + var userDetails = k8SConfig.Users.FirstOrDefault(c => c.Name.Equals(activeContext.ContextDetails.User, StringComparison.OrdinalIgnoreCase)); + if (userDetails == null) { - throw new KubeConfigException("User not found for the current context in kubeconfig"); + throw new KubeConfigException("User not found for context {activeContext.Name} in kubeconfig"); } if (userDetails.UserCredentials == null) @@ -229,7 +211,7 @@ namespace k8s if (!userCredentialsFound) { - throw new KubeConfigException($"User: {userDetails.Name} does not have appropriate auth credentials in kube config"); + throw new KubeConfigException($"User: {userDetails.Name} does not have appropriate auth credentials in kubeconfig"); } } diff --git a/src/Utils.cs b/src/Utils.cs index 4db4fa6..af3801f 100644 --- a/src/Utils.cs +++ b/src/Utils.cs @@ -1,8 +1,9 @@ namespace k8s { + using k8s.Exceptions; using System; + using System.ComponentModel; using System.Diagnostics; - using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -50,7 +51,8 @@ var filePrefix = config.CurrentContext; var pfxFilePath = Path.Combine(certDirPath, filePrefix + "pfx"); - if (!string.IsNullOrWhiteSpace(config.ClientCertificateKey)) { + if (!string.IsNullOrWhiteSpace(config.ClientCertificateKey)) + { keyFilePath = Path.Combine(certDirPath, filePrefix + "key"); using (FileStream fs = File.Create(keyFilePath)) { @@ -58,24 +60,27 @@ await fs.WriteAsync(info, 0, info.Length).ConfigureAwait(false); } } - if (!string.IsNullOrWhiteSpace(config.ClientKey)) { + if (!string.IsNullOrWhiteSpace(config.ClientKey)) + { keyFilePath = config.ClientKey; } - if (!string.IsNullOrWhiteSpace(config.ClientCertificateData)) { + if (!string.IsNullOrWhiteSpace(config.ClientCertificateData)) + { certFilePath = Path.Combine(certDirPath, filePrefix + "cert"); - + using (FileStream fs = File.Create(certFilePath)) { byte[] info = Convert.FromBase64String(config.ClientCertificateData); await fs.WriteAsync(info, 0, info.Length).ConfigureAwait(false); } } - if (!string.IsNullOrWhiteSpace(config.ClientCertificate)) { + if (!string.IsNullOrWhiteSpace(config.ClientCertificate)) + { certFilePath = config.ClientCertificate; } - var process = new Process(); - process.StartInfo = new ProcessStartInfo() + + var processStartInfo = new ProcessStartInfo { FileName = @"openssl", Arguments = $"pkcs12 -export -out {pfxFilePath} -inkey {keyFilePath} -in {certFilePath} -passout pass:", @@ -84,14 +89,23 @@ RedirectStandardOutput = true }; - process.Start(); - process.WaitForExit(); - if (process.ExitCode == 0) + try { - return pfxFilePath; + using (Process process = Process.Start(processStartInfo)) + { + process.WaitForExit(); + if (process.ExitCode != 0) + { + throw new KubernetesClientException($"Failed to generate pfx file with openssl. ExitCode = {process.ExitCode}."); + } + } + } + catch (Win32Exception e) + { + throw new KubernetesClientException("Failed to generate pfx file with openssl.", e); } - return null; + return pfxFilePath; } } } diff --git a/tests/KubernetesClientConfigurationTests.cs b/tests/KubernetesClientConfigurationTests.cs index c4baefb..2ac872f 100755 --- a/tests/KubernetesClientConfigurationTests.cs +++ b/tests/KubernetesClientConfigurationTests.cs @@ -1,6 +1,4 @@ -using System; -using Xunit; -using k8s; +using Xunit; using System.IO; namespace k8s.Tests