public void CreatedFromPreLoadedConfig() { var k8sConfig = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo("assets/kubeconfig.yml"), useRelativePaths: false); var cfg = KubernetesClientConfiguration.BuildConfigFromConfigObject(k8sConfig); Assert.NotNull(cfg.Host); }
public void SetK8SConfiguration(string config) { K8SConfiguration = KubernetesClientConfiguration.LoadKubeConfig(config.ToStream()); Context = K8SConfiguration.CurrentContext; RaisePropertyChanged(State.ConfigNotification); }
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.Equal(1, cfg.Extensions.Count); Assert.Equal(1, cfg.Preferences.Count); }
public void LoadKubeConfigExplicitFilePath() { var txt = File.ReadAllText("assets/kubeconfig.yml"); var expectedCfg = Yaml.LoadFromString <K8SConfiguration>(txt); var cfg = KubernetesClientConfiguration.LoadKubeConfig("assets/kubeconfig.yml"); Assert.NotNull(cfg); AssertConfigEqual(expectedCfg, cfg); }
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); }
public void LoadSameKubeConfigFromEnvironmentVariableUnmodified() { var txt = File.ReadAllText("assets/kubeconfig.yml"); var expectedCfg = Yaml.LoadFromString <K8SConfiguration>(txt); var fileInfo = new FileInfo(Path.GetFullPath("assets/kubeconfig.yml")); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { fileInfo, fileInfo }); AssertConfigEqual(expectedCfg, cfg); }
public void LoadKubeConfigWithAdditionalProperties() { var txt = File.ReadAllText("assets/kubeconfig.additional-properties.yml"); var expectedCfg = Yaml.LoadFromString <K8SConfiguration>(txt); var fileInfo = new FileInfo(Path.GetFullPath("assets/kubeconfig.additional-properties.yml")); var cfg = KubernetesClientConfiguration.LoadKubeConfig(new FileInfo[] { fileInfo, fileInfo }); AssertConfigEqual(expectedCfg, cfg); }
public void LoadKubeConfigFileInfo() { var filePath = "assets/kubeconfig.yml"; var txt = File.ReadAllText(filePath); var expectedCfg = Yaml.LoadFromString <K8SConfiguration>(txt); var fileInfo = new FileInfo(filePath); var cfg = KubernetesClientConfiguration.LoadKubeConfig(fileInfo); Assert.NotNull(cfg); AssertConfigEqual(expectedCfg, cfg); }
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); }
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()); }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); try { KubernetesClientConfiguration.LoadKubeConfig(); } catch (Exception e) { _hasStartupFailed = true; _startupFailureMessage = e.ToString(); } if (_hasStartupFailed) { return; } services.AddTransient(provider => { var configFile = KubernetesClientConfiguration.LoadKubeConfig(); configFile.CurrentContext = InMemoryUserPreferencesStore.CurrentContextName ?? configFile.CurrentContext; var config = KubernetesClientConfiguration.BuildConfigFromConfigObject(configFile); return(new Kubernetes(config)); }); services.AddSingleton <KubernetesHelper>(); services.AddSingleton <EntityReferenceUrlBuilder>(); services.AddSingleton <KubernetesCommandLineBuilder>(); services.AddBlazoredSessionStorage(); services.AddClipboard(); services.AddBootstrapCss(); var fusion = services.AddFusion(); services.AddSingleton(c => new UpdateDelayer.Options() { // Default update delayer options Delay = TimeSpan.FromSeconds(0.1), }); fusion.AddComputeService <IKubeConfigLoader, KubeConfigLoader>(); RegisterFusionDb(fusion); services.AttributeBased().AddServicesFrom(Assembly.GetExecutingAssembly()); }
public void LoadKubeConfigStream() { var filePath = "assets/kubeconfig.yml"; var txt = File.ReadAllText(filePath); var expectedCfg = Yaml.LoadFromString <K8SConfiguration>(txt); var fileInfo = new FileInfo(filePath); K8SConfiguration cfg; using (var stream = fileInfo.OpenRead()) { cfg = KubernetesClientConfiguration.LoadKubeConfig(stream); } Assert.NotNull(cfg); AssertConfigEqual(expectedCfg, cfg); }
public List <Context> GetAllContexts() { var k8SConfig = KubernetesClientConfiguration.LoadKubeConfig(); var contexts = new List <Context>(); foreach (var c in k8SConfig.Contexts) { var context = new Context { Cluster = c.ContextDetails.Cluster, Name = c.Name, Namespace = string.IsNullOrEmpty(c.Namespace) ? "" : c.Namespace, User = c.ContextDetails.User, Current = c.ContextDetails.Cluster == k8SConfig.CurrentContext ? "*" : "" }; contexts.Add(context); } return(contexts); }
public State(ILogger <State> logger) { Logger = logger; try { K8SConfiguration = KubernetesClientConfiguration.LoadKubeConfig(); Context = K8SConfiguration.CurrentContext; } catch (KubeConfigException) { Logger.LogInformation("No kube config found"); K8SConfiguration = new K8SConfiguration { FileName = "config", Clusters = new List <Cluster>() { new Cluster() { Name = "localhost:8001", ClusterEndpoint = new ClusterEndpoint() { Server = "http://localhost:8001" } } }, Contexts = new List <Context>() { new Context() { Name = "localhost:8001", ContextDetails = new ContextDetails() { Cluster = "localhost:8001" } } } }; Context = "localhost:8001"; } }
static async Task <List <Pod> > GetAllPods(string[] excludeClusters, int timeoutSeconds) { var config = KubernetesClientConfiguration.LoadKubeConfig(); var clusters = new List <string>(); foreach (var context in config.Contexts.OrderBy(c => c.Name)) { if (excludeClusters.Any(e => context.Name.Contains(e))) { Console.WriteLine($"Excluding cluster: '{context.Name}'"); continue; } clusters.Add(context.Name); } var allpods = new List <Task <List <Pod> > >(); foreach (var cluster in clusters) { KubernetesClientConfiguration clientConfig; try { clientConfig = KubernetesClientConfiguration.BuildConfigFromConfigObject(config, cluster); } catch (KubeConfigException ex) { Console.WriteLine($"Ignoring cluster (invalid config): '{cluster}': {ex.Message}"); continue; } Console.WriteLine($"Connecting to: {clientConfig.Host} ({cluster})"); IKubernetes client = new Kubernetes(clientConfig); allpods.Add(GetPods(client, cluster, timeoutSeconds)); } await Task.WhenAll(allpods); return(allpods.SelectMany(t => t.Result).ToList()); }
public override async Task ExecuteAsync(OutputContext output, ApplicationBuilder application, ServiceBuilder service) { var bindings = service.Outputs.OfType <ComputedBindings>().FirstOrDefault(); if (bindings is null) { return; } foreach (var binding in bindings.Bindings) { if (binding is SecretInputBinding secretInputBinding) { if (!Secrets.Add(secretInputBinding.Name)) { output.WriteDebugLine($"Already validated secret '{secretInputBinding.Name}'."); continue; } output.WriteDebugLine($"Validating secret '{secretInputBinding.Name}'."); var config = KubernetesClientConfiguration.BuildDefaultConfig(); // Workaround for https://github.com/kubernetes-client/csharp/issues/372 var store = KubernetesClientConfiguration.LoadKubeConfig(); var context = store.Contexts.Where(c => c.Name == config.CurrentContext).FirstOrDefault(); config.Namespace ??= context?.ContextDetails?.Namespace; var kubernetes = new Kubernetes(config); try { var result = await kubernetes.ReadNamespacedSecretWithHttpMessagesAsync(secretInputBinding.Name, config.Namespace ?? "default"); output.WriteInfoLine($"Found existing secret '{secretInputBinding.Name}'."); continue; } catch (HttpOperationException ex) when(ex.Response.StatusCode == HttpStatusCode.NotFound) { // The kubernetes client uses exceptions for 404s. } catch (Exception ex) { output.WriteDebugLine("Failed to query secret."); output.WriteDebugLine(ex.ToString()); throw new CommandException("Unable connect to kubernetes.", ex); } if (Force) { output.WriteDebugLine("Skipping because force was specified."); continue; } if (!Interactive) { throw new CommandException( $"The secret '{secretInputBinding.Name}' used for service '{secretInputBinding.Service.Name}' is missing from the deployment environment. " + $"Rerun the command with --interactive to specify the value interactively, or with --force to skip validation. Alternatively " + $"use the following command to manually create the secret." + System.Environment.NewLine + $"kubectl create secret generic {secretInputBinding.Name} --from-literal=connectionstring=<value>"); } // If we get here then we should create the sceret. var text = output.Prompt($"Enter the connection string to use for service '{secretInputBinding.Service.Name}'", allowEmpty: true); if (string.IsNullOrWhiteSpace(text)) { output.WriteAlways($"Skipping creation of secret for '{secretInputBinding.Service.Name}'. This may prevent creation of pods until secrets are created."); output.WriteAlways($"Manually create a secret with:"); output.WriteAlways($"kubectl create secret generic {secretInputBinding.Name} --from-literal=connectionstring=<value>"); continue; } var secret = new V1Secret(type: "Opaque", stringData: new Dictionary <string, string>() { { "connectionstring", text }, }); secret.Metadata = new V1ObjectMeta(); secret.Metadata.Name = secretInputBinding.Name; output.WriteDebugLine($"Creating secret '{secret.Metadata.Name}'."); try { await kubernetes.CreateNamespacedSecretWithHttpMessagesAsync(secret, config.Namespace ?? "default"); output.WriteInfoLine($"Created secret '{secret.Metadata.Name}'."); } catch (Exception ex) { output.WriteDebugLine("Failed to create secret."); output.WriteDebugLine(ex.ToString()); throw new CommandException("Failed to create secret.", ex); } } } var yaml = service.Outputs.OfType <IYamlManifestOutput>().ToArray(); if (yaml.Length == 0) { output.WriteDebugLine($"No yaml manifests found for service '{service.Name}'. Skipping."); return; } using var tempFile = TempFile.Create(); output.WriteDebugLine($"Writing output to '{tempFile.FilePath}'."); { using var stream = File.OpenWrite(tempFile.FilePath); using var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: -1, leaveOpen: true); var yamlStream = new YamlStream(yaml.Select(y => y.Yaml)); yamlStream.Save(writer, assignAnchors: false); } // kubectl apply logic is implemented in the client in older versions of k8s. The capability // to get the same behavior in the server isn't present in every version that's relevant. // // https://kubernetes.io/docs/reference/using-api/api-concepts/#server-side-apply // output.WriteDebugLine("Running 'kubectl apply'."); output.WriteCommandLine("kubectl", $"apply -f \"{tempFile.FilePath}\""); var capture = output.Capture(); var exitCode = await Process.ExecuteAsync( $"kubectl", $"apply -f \"{tempFile.FilePath}\"", System.Environment.CurrentDirectory, stdOut : capture.StdOut, stdErr : capture.StdErr); output.WriteDebugLine($"Done running 'kubectl apply' exit code: {exitCode}"); if (exitCode != 0) { throw new CommandException("'kubectl apply' failed."); } output.WriteInfoLine($"Deployed service '{service.Name}'."); }