using k8s.Authentication; using k8s.Exceptions; using k8s.KubeConfigModels; using System; using System.Collections.Generic; using System.IO; using System.IO.Abstractions; using System.IO.Abstractions.TestingHelpers; using System.Linq; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Xunit; namespace k8s.Tests { public class KubernetesClientConfigurationTests : IDisposable { /// /// Not all tests set these, but no harm in clearing them. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_HOST", null); Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_PORT", null); } /// /// Check if host is properly loaded, per context /// /// Context to retreive the configuration /// Host to check [Theory] [InlineData("federal-context", "https://horse.org:4443")] [InlineData("queen-anne-context", "https://pig.org:443")] public void ContextHost(string context, string host) { var fi = new FileInfo("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context, useRelativePaths: false); Assert.Equal(host, cfg.Host); } /// /// Check if namespace is properly loaded, per context /// /// Context to retreive the configuration /// Namespace to check [Theory] [InlineData("federal-context", "chisel-ns")] [InlineData("queen-anne-context", "saw-ns")] public void ContextNamespace(string context, string @namespace) { var fi = new FileInfo("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context, useRelativePaths: false); Assert.Equal(@namespace, cfg.Namespace); } /// /// Checks if user-based token is loaded properly from the config file, per context /// /// Context to retreive the configuration /// User authentication token [Theory] [InlineData("queen-anne-context", "black-token")] public void ContextUserToken(string context, string token) { var fi = new FileInfo("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context); Assert.Equal(context, cfg.CurrentContext); Assert.Null(cfg.Username); Assert.Equal(token, cfg.AccessToken); } /// /// Checks if certificate-based authentication is loaded properly from the config file, per context /// /// Context to retreive the configuration /// 'client-certificate-data' node content /// 'client-key-data' content [Theory] [InlineData("federal-context", "assets/client.crt", "assets/client.key")] public void ContextCertificate(string context, string clientCert, string clientCertKey) { var fi = new FileInfo("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context, useRelativePaths: false); Assert.Equal(context, cfg.CurrentContext); Assert.Equal(cfg.ClientCertificateFilePath, clientCert); Assert.Equal(cfg.ClientKeyFilePath, clientCertKey); } /// /// Checks for loading of elliptical curve keys /// /// Context to retreive the configuration [Theory] [InlineData("elliptic-context")] public void ContextEllipticKey(string context) { var fi = new FileInfo("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context, useRelativePaths: false); var pfx = CertUtils.GeneratePfx(cfg); Assert.NotNull(pfx); } /// /// Checks if certificate-based authentication is loaded properly from the config file, per context /// /// Context to retreive the configuration [Theory] [InlineData("victorian-context")] public void ClientData(string context) { var fi = new FileInfo("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, context); Assert.Equal(context, cfg.CurrentContext); Assert.NotNull(cfg.SslCaCerts); Assert.Equal(File.ReadAllText("assets/client-certificate-data.txt"), cfg.ClientCertificateData); Assert.Equal(File.ReadAllText("assets/client-key-data.txt"), cfg.ClientCertificateKeyData); } /// /// Checks that a KubeConfigException is thrown when no certificate-authority-data is set and user do not require tls /// skip /// [Fact] public void CheckClusterTlsSkipCorrectness() { var fi = new FileInfo("assets/kubeconfig.tls-skip.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi); Assert.NotNull(cfg.Host); Assert.Null(cfg.SslCaCerts); Assert.True(cfg.SkipTlsVerify); } /// /// Checks that a KubeConfigException is not thrown when no certificate-authority-data is set and user do not require tls /// skip /// [Fact] public void CheckClusterTlsNoSkipCorrectness() { var fi = new FileInfo("assets/kubeconfig.tls-no-skip.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi); Assert.NotNull(cfg.Host); Assert.Null(cfg.SslCaCerts); Assert.False(cfg.SkipTlsVerify); } /// /// Checks that a KubeConfigException is thrown when the cluster defined in clusters and contexts do not match /// [Fact] public void ClusterNameMissmatch() { var fi = new FileInfo("assets/kubeconfig.cluster-missmatch.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi)); } /// /// Checks that a KubeConfigException is thrown when the clusters section is missing /// [Fact] public void ClusterNotFound() { var fi = new FileInfo("assets/kubeconfig.no-cluster.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi)); } /// /// The configuration file is not present. An KubeConfigException should be thrown /// [Fact] public void ConfigurationFileNotFound() { var fi = new FileInfo("/path/to/nowhere"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi)); } /// /// Test that an Exception is thrown when initializating a KubernetClientConfiguration whose config file Context is not /// present /// [Fact] public void ContextNotFound() { var fi = new FileInfo("assets/kubeconfig.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "context-not-found")); } [Fact] public void CreatedFromPreLoadedConfig() { var k8sConfig = KubernetesClientConfiguration.LoadKubeConfig( new FileInfo("assets/kubeconfig.yml"), false); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigObject(k8sConfig); Assert.NotNull(cfg.Host); } /// /// Checks Host is loaded from the default configuration file /// [Fact] public void DefaultConfigurationLoaded() { var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile( new FileInfo("assets/kubeconfig.yml"), useRelativePaths: false); Assert.NotNull(cfg.Host); } /// /// Checks that a KubeConfigException is thrown when incomplete user credentials /// [Fact] public void IncompleteUserCredentials() { var fi = new FileInfo("assets/kubeconfig.no-credentials.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false)); } /// /// Test if KubeConfigException is thrown when no Contexts and we use the default context name /// [Fact] public void NoContexts() { var fi = new FileInfo("assets/kubeconfig.no-context.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi)); } /// /// Test if KubeConfigException is thrown when no Contexts are set and we specify a concrete context name /// [Fact] public void NoContextsExplicit() { var fi = new FileInfo("assets/kubeconfig-no-context.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "context")); } /// /// Checks that a KubeConfigException is thrown when the current context exists but has no details specified /// [Fact] public void ContextNoDetails() { var fi = new FileInfo("assets/kubeconfig.no-context-details.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi)); } /// /// Checks that a KubeConfigException is thrown when the server property is not set in cluster /// [Fact] public void ServerNotFound() { var fi = new FileInfo("assets/kubeconfig.no-server.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi)); } /// /// Checks user/password authentication information is read properly /// [Fact] public void UserPasswordAuthentication() { var fi = new FileInfo("assets/kubeconfig.user-pass.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false); Assert.Equal("admin", cfg.Username); Assert.Equal("secret", cfg.Password); } /// /// Checks oidc authentication provider information is read properly /// [Fact] public void UserOidcAuthentication() { var fi = new FileInfo("assets/kubeconfig.user-oidc.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false); Assert.Equal("ID_TOKEN", cfg.AccessToken); Assert.IsType(cfg.TokenProvider); } /// /// Checks that a KubeConfigException is thrown when user cannot be found in users /// [Fact] public void UserNotFound() { var fi = new FileInfo("assets/kubeconfig.user-not-found.yml"); Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false)); } /// /// Make sure that user is not a necessary field. set #issue 24 /// [Fact] public void EmptyUserNotFound() { var fi = new FileInfo("assets/kubeconfig.no-user.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, useRelativePaths: false); Assert.NotEmpty(cfg.Host); } /// /// Make sure Host is replaced by masterUrl /// [Fact] public void OverrideByMasterUrl() { var fi = new FileInfo("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, masterUrl: "http://test.server", useRelativePaths: false); Assert.Equal("http://test.server", cfg.Host); } /// /// Make sure that http urls are loaded even if insecure-skip-tls-verify === true /// [Fact] public void SmartSkipTlsVerify() { var fi = new FileInfo("assets/kubeconfig.tls-skip-http.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi); Assert.False(cfg.SkipTlsVerify); Assert.Equal("http://horse.org", cfg.Host); } /// /// Make sure that TlsServerName is present /// [Fact] public void TlsServerName() { var fi = new FileInfo("assets/kubeconfig.tls-servername.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi); Assert.Equal("pony", cfg.TlsServerName); } /// /// Checks config could work well when current-context is not set but masterUrl is set. #issue 24 /// [Fact] public void NoCurrentContext() { var fi = new FileInfo("assets/kubeconfig.no-current-context.yml"); // failed if cannot infer any server host Assert.Throws(() => KubernetesClientConfiguration.BuildConfigFromConfigFile(fi)); // survive when masterUrl is set var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, masterUrl: "http://test.server"); Assert.Equal("http://test.server", cfg.Host); } /// /// Checks that loading a configuration from a file leaves no outstanding handles to the file. /// /// /// This test fails only on Windows. /// [Fact] public void DeletedConfigurationFile() { var assetFileInfo = new FileInfo("assets/kubeconfig.yml"); var tempFileInfo = new FileInfo(Path.GetTempFileName()); File.Copy(assetFileInfo.FullName, tempFileInfo.FullName, /* overwrite: */ true); KubernetesClientConfiguration config; try { config = KubernetesClientConfiguration.BuildConfigFromConfigFile(tempFileInfo, useRelativePaths: false); } finally { File.Delete(tempFileInfo.FullName); } } /// /// Checks Host is loaded from the default configuration file as string /// [Fact] public void DefaultConfigurationAsStringLoaded() { var filePath = "assets/kubeconfig.yml"; var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, false); Assert.NotNull(cfg.Host); } /// /// Checks Host is loaded from the default configuration file as stream /// [Fact] public void DefaultConfigurationAsStreamLoaded() { using var stream = File.OpenRead("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(stream); Assert.NotNull(cfg.Host); } /// /// Checks users.as-user-extra is loaded correctly from a configuration file. /// [Fact] public void AsUserExtra() { var filePath = "assets/kubeconfig.as-user-extra.yml"; var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, false); Assert.NotNull(cfg.Host); } [Fact] public async Task ContextWithClusterExtensions() { var path = Path.GetFullPath("assets/kubeconfig.cluster-extensions.yml"); _ = await KubernetesClientConfiguration.BuildConfigFromConfigFileAsync(new FileInfo(path)).ConfigureAwait(false); } [Fact] public void ContextWithWildcardIPv4() { var path = Path.GetFullPath("assets/kubeconfig.wildcard-ipv4.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(path); Assert.Equal("https://127.0.0.1:443/", cfg.Host); } [Fact] public void ContextWithWildcardIPv6() { var path = Path.GetFullPath("assets/kubeconfig.wildcard-ipv6.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(path); Assert.Equal("https://[::1]:443/", cfg.Host); } [Fact] public void ContextWithWildcardIPv62() { var path = Path.GetFullPath("assets/kubeconfig.wildcard-ipv6.yml"); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(path); Assert.Equal("https://[::1]:443/", cfg.Host); } /// /// Ensures Kube config file is loaded from explicit file /// [Fact] public void LoadKubeConfigExplicitFilePath() { var txt = File.ReadAllText("assets/kubeconfig.yml"); var expectedCfg = KubernetesYaml.Deserialize(txt); var cfg = KubernetesClientConfiguration.LoadKubeConfig("assets/kubeconfig.yml"); Assert.NotNull(cfg); AssertConfigEqual(expectedCfg, cfg); } [Fact] public void LoadKubeConfigFileInfo() { var filePath = "assets/kubeconfig.yml"; var txt = File.ReadAllText(filePath); var expectedCfg = KubernetesYaml.Deserialize(txt); var fileInfo = new FileInfo(filePath); var cfg = KubernetesClientConfiguration.LoadKubeConfig(fileInfo); Assert.NotNull(cfg); AssertConfigEqual(expectedCfg, cfg); } [Fact] public void LoadKubeConfigStream() { var filePath = "assets/kubeconfig.yml"; var txt = File.ReadAllText(filePath); var expectedCfg = KubernetesYaml.Deserialize(txt); var fileInfo = new FileInfo(filePath); K8SConfiguration cfg; using (var stream = fileInfo.OpenRead()) { cfg = KubernetesClientConfiguration.LoadKubeConfig(stream); } Assert.NotNull(cfg); AssertConfigEqual(expectedCfg, cfg); } [Fact] public void LoadKubeConfigFromEnvironmentVariable() { // BuildDefaultConfig assumes UseRelativePaths: true, which isn't // done by any tests. var filePath = Path.GetFullPath("assets/kubeconfig.relative.yml"); var environmentVariable = "KUBECONFIG_LoadKubeConfigFromEnvironmentVariable"; Environment.SetEnvironmentVariable(environmentVariable, filePath); KubernetesClientConfiguration.KubeConfigEnvironmentVariable = environmentVariable; var cfg = KubernetesClientConfiguration.BuildDefaultConfig(); Assert.NotNull(cfg); } [Fact] public void LoadKubeConfigFromEnvironmentVariableMultipleConfigs() { // This test makes sure that a list of environment variables works (no exceptions), // doesn't check validity of configuration, which is done in other tests. var filePath = Path.GetFullPath("assets/kubeconfig.relative.yml"); var environmentVariable = "KUBECONFIG_LoadKubeConfigFromEnvironmentVariable_MultipleConfigs"; Environment.SetEnvironmentVariable( environmentVariable, string.Concat(filePath, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ';' : ':', filePath)); KubernetesClientConfiguration.KubeConfigEnvironmentVariable = environmentVariable; var cfg = KubernetesClientConfiguration.BuildDefaultConfig(); Assert.NotNull(cfg); } [Fact] public void LoadSameKubeConfigFromEnvironmentVariableUnmodified() { var txt = File.ReadAllText("assets/kubeconfig.yml"); var expectedCfg = KubernetesYaml.Deserialize(txt); var fileInfo = new FileInfo(Path.GetFullPath("assets/kubeconfig.yml")); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { fileInfo, fileInfo }); AssertConfigEqual(expectedCfg, cfg); } [Fact] public void LoadKubeConfigWithAdditionalProperties() { var txt = File.ReadAllText("assets/kubeconfig.additional-properties.yml"); Assert.Throws(() => KubernetesYaml.Deserialize(txt, strict: true)); var expectedCfg = KubernetesYaml.Deserialize(txt); var fileInfo = new FileInfo(Path.GetFullPath("assets/kubeconfig.additional-properties.yml")); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { fileInfo, fileInfo }); AssertConfigEqual(expectedCfg, cfg); } [Fact] public void MergeKubeConfigNoDuplicates() { var firstPath = Path.GetFullPath("assets/kubeconfig.as-user-extra.yml"); var secondPath = Path.GetFullPath("assets/kubeconfig.yml"); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(firstPath), new FileInfo(secondPath), }); // Merged file has 6 users now. Assert.Equal(6, cfg.Users.Count()); Assert.Equal(5, cfg.Clusters.Count()); Assert.Equal(5, cfg.Contexts.Count()); } [Fact] public void AlwaysPicksFirstOccurence() { var firstPath = Path.GetFullPath("assets/kubeconfig.no-cluster.yml"); var secondPath = Path.GetFullPath("assets/kubeconfig.no-context.yml"); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(firstPath), new FileInfo(secondPath), }); var user = cfg.Users.Where(u => u.Name == "green-user").Single(); Assert.NotNull(user.UserCredentials.Password); Assert.Null(user.UserCredentials.ClientCertificate); } [Fact] public void ContextFromSecondWorks() { var firstPath = Path.GetFullPath("assets/kubeconfig.no-current-context.yml"); var secondPath = Path.GetFullPath("assets/kubeconfig.no-user.yml"); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(firstPath), new FileInfo(secondPath), }); // green-user Assert.NotNull(cfg.CurrentContext); } [Fact] public void ContextPreferencesExtensionsMergeWithDuplicates() { var path = Path.GetFullPath("assets/kubeconfig.preferences-extensions.yml"); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { new FileInfo(path), new FileInfo(path), }); Assert.Single(cfg.Extensions); Assert.Single(cfg.Preferences); } /// /// Ensures Kube config file can be loaded from within a non-default . /// The use of ensures the test is run from within a UI-like . /// [UIFact] public void BuildConfigFromConfigFileInfoOnNonDefaultSynchronizationContext() { var fi = new FileInfo("assets/kubeconfig.yml"); KubernetesClientConfiguration.BuildConfigFromConfigFile(fi, "federal-context", useRelativePaths: false); } private void AssertConfigEqual(K8SConfiguration expected, K8SConfiguration actual) { Assert.Equal(expected.ApiVersion, actual.ApiVersion); Assert.Equal(expected.CurrentContext, actual.CurrentContext); foreach (var expectedContext in expected.Contexts) { // Will throw exception if not found var actualContext = actual.Contexts.First(c => c.Name.Equals(expectedContext.Name)); AssertContextEqual(expectedContext, actualContext); } foreach (var expectedCluster in expected.Clusters) { // Will throw exception if not found var actualCluster = actual.Clusters.First(c => c.Name.Equals(expectedCluster.Name)); AssertClusterEqual(expectedCluster, actualCluster); } foreach (var expectedUser in expected.Users) { // Will throw exception if not found var actualUser = actual.Users.First(u => u.Name.Equals(expectedUser.Name)); AssertUserEqual(expectedUser, actualUser); } } private static void AssertContextEqual(Context expected, Context actual) { Assert.Equal(expected.Name, actual.Name); Assert.Equal(expected.ContextDetails.Cluster, actual.ContextDetails.Cluster); Assert.Equal(expected.ContextDetails.User, actual.ContextDetails.User); Assert.Equal(expected.ContextDetails.Namespace, actual.ContextDetails.Namespace); } private static void AssertClusterEqual(Cluster expected, Cluster actual) { Assert.Equal(expected.Name, actual.Name); Assert.Equal(expected.ClusterEndpoint.CertificateAuthority, actual.ClusterEndpoint.CertificateAuthority); Assert.Equal( expected.ClusterEndpoint.CertificateAuthorityData, actual.ClusterEndpoint.CertificateAuthorityData); Assert.Equal(expected.ClusterEndpoint.Server, actual.ClusterEndpoint.Server); Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify); } private static void AssertUserEqual(User expected, User actual) { Assert.Equal(expected.Name, actual.Name); var expectedCreds = expected.UserCredentials; var actualCreds = actual.UserCredentials; Assert.Equal(expectedCreds.ClientCertificateData, actualCreds.ClientCertificateData); Assert.Equal(expectedCreds.ClientCertificate, actualCreds.ClientCertificate); Assert.Equal(expectedCreds.ClientKeyData, actualCreds.ClientKeyData); Assert.Equal(expectedCreds.ClientKey, actualCreds.ClientKey); Assert.Equal(expectedCreds.Token, actualCreds.Token); Assert.Equal(expectedCreds.Impersonate, actualCreds.Impersonate); Assert.Equal(expectedCreds.UserName, actualCreds.UserName); Assert.Equal(expectedCreds.Password, actualCreds.Password); Assert.True(expectedCreds.ImpersonateGroups.All(x => actualCreds.ImpersonateGroups.Contains(x))); Assert.True(expectedCreds.ImpersonateUserExtra.All(x => actualCreds.ImpersonateUserExtra.Contains(x))); if (expectedCreds.AuthProvider != null) { Assert.True(expectedCreds.AuthProvider.Config.All(x => actualCreds.AuthProvider.Config.Contains(x))); } } private class FileSystemAdapter : FileSystem.IFileSystem { private readonly IFileSystem io; public FileSystemAdapter(System.IO.Abstractions.IFileSystem io) { this.io = io; } public bool Exists(string path) { return io.File.Exists(path); } public Stream OpenRead(string path) { return io.File.OpenRead(path); } public string ReadAllText(string path) { return io.File.ReadAllText(path); } } /// /// Test in cluster configuration. /// [Fact] public void IsInCluster() { Assert.False(KubernetesClientConfiguration.IsInCluster()); Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_HOST", "kubernetes"); Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_PORT", "443"); var tokenPath = Path.Combine(KubernetesClientConfiguration.ServiceAccountPath, KubernetesClientConfiguration.ServiceAccountTokenKeyFileName); var certPath = Path.Combine(KubernetesClientConfiguration.ServiceAccountPath, KubernetesClientConfiguration.ServiceAccountRootCAKeyFileName); var fileSystem = new MockFileSystem(new Dictionary { { tokenPath, new MockFileData("foo") }, { certPath, new MockFileData("bar") }, }); using (FileSystem.With(new FileSystemAdapter(fileSystem))) { Assert.True(KubernetesClientConfiguration.IsInCluster()); } } /// /// Test in cluster configuration loading. /// [Fact] public void LoadInCluster() { Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_HOST", "other.default.svc"); Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_PORT", "443"); var tokenPath = Path.Combine(KubernetesClientConfiguration.ServiceAccountPath, KubernetesClientConfiguration.ServiceAccountTokenKeyFileName); var certPath = Path.Combine(KubernetesClientConfiguration.ServiceAccountPath, KubernetesClientConfiguration.ServiceAccountRootCAKeyFileName); var fileSystem = new MockFileSystem(new Dictionary { { tokenPath, new MockFileData("foo") }, { certPath, new MockFileData("bar") }, }); using (FileSystem.With(new FileSystemAdapter(fileSystem))) { var config = KubernetesClientConfiguration.InClusterConfig(); Assert.Equal("https://other.default.svc:443/", config.Host); Assert.Null(config.Namespace); } } /// /// Test in cluster configuration loading of namespaces. /// [Fact] public void LoadInClusterNamespace() { Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_HOST", "kubernetes.default.svc"); Environment.SetEnvironmentVariable("KUBERNETES_SERVICE_PORT", "443"); var tokenPath = Path.Combine(KubernetesClientConfiguration.ServiceAccountPath, KubernetesClientConfiguration.ServiceAccountTokenKeyFileName); var certPath = Path.Combine(KubernetesClientConfiguration.ServiceAccountPath, KubernetesClientConfiguration.ServiceAccountRootCAKeyFileName); var namespacePath = Path.Combine(KubernetesClientConfiguration.ServiceAccountPath, KubernetesClientConfiguration.ServiceAccountNamespaceFileName); var fileSystem = new MockFileSystem(new Dictionary { { tokenPath, new MockFileData("foo") }, { certPath, new MockFileData("bar") }, { namespacePath, new MockFileData("some namespace") }, }); using (FileSystem.With(new FileSystemAdapter(fileSystem))) { var config = KubernetesClientConfiguration.InClusterConfig(); Assert.Equal("https://kubernetes.default.svc:443/", config.Host); Assert.Equal("some namespace", config.Namespace); } } } }