private KubeClientOptions GetKubeClientOptions(ClusterConnection settings) { switch (settings.Kind) { case ConfigKind.NoAuthentication: return(new KubeClientOptions { ApiEndPoint = new Uri(settings.Url), AuthStrategy = KubeAuthStrategy.None, AllowInsecure = settings.AllowInsecure, // Don't validate server certificate KubeNamespace = settings.DefaultNamespace, }); case ConfigKind.KubeConfigFile: return(K8sConfig.Load(settings.KubeConfigFile).ToKubeClientOptions( kubeContextName: settings.DefaultContext, defaultKubeNamespace: settings.DefaultNamespace )); case ConfigKind.BearerToken: return(new KubeClientOptions { ApiEndPoint = new Uri(settings.Url), AuthStrategy = KubeAuthStrategy.BearerToken, AccessToken = settings.AccessToken, AllowInsecure = settings.AllowInsecure, // Don't validate server certificate KubeNamespace = settings.DefaultNamespace, }); default: throw new ArgumentOutOfRangeException(); } }
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken) { await base.ProcessRecordAsync(cancellationToken); K8sConfig config = K8sConfig.Load(); WriteObject(config); }
private static KubeClientOptions GetKubeClientOptions() { var options = string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST")) ? K8sConfig.Load().ToKubeClientOptions() : KubeClientOptions.FromPodServiceAccount(); options.KubeNamespace = "default"; return(options); }
public void LinuxUsesHomeEnvironmentVariable() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { Environment.SetEnvironmentVariable("USERPROFILE", UserProfile); var home = Environment.GetEnvironmentVariable("HOME"); var config = K8sConfig.Locate(); Assert.Equal(Path.Combine(home, ".kube", "config"), config); } }
public void WindowsUsesHomeFirst() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Environment.SetEnvironmentVariable("USERPROFILE", UserProfile); Environment.SetEnvironmentVariable("HOMEDRIVE", HomeDrive); Environment.SetEnvironmentVariable("HOMEPATH", HomePath); Environment.SetEnvironmentVariable("HOME", Home); var config = K8sConfig.Locate(); Assert.Equal(Path.Combine(Home, ".kube", "config"), config); } }
public void WindowsUsesUserProfileAsLastOption() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Environment.SetEnvironmentVariable("HOME", String.Empty); Environment.SetEnvironmentVariable("HOMEDRIVE", String.Empty); Environment.SetEnvironmentVariable("HOMEPATH", String.Empty); Environment.SetEnvironmentVariable("USERPROFILE", UserProfile); var config = K8sConfig.Locate(); Assert.Equal(Path.Combine(UserProfile, ".kube", "config"), config); } }
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken) { await base.ProcessRecordAsync(cancellationToken); Serializer serializer = new SerializerBuilder().Build(); string yaml = serializer.Serialize(Config); string configPath = K8sConfig.Locate(); if (ShouldProcess(configPath, "update")) { await File.WriteAllTextAsync(configPath, yaml); // Do not pass cancellationToken to not corrupt config file } }
public void CanDeserializeCredentialPluginConfiguration(string configName) { FileInfo configFile = new FileInfo( Path.Combine("Configurations", $"{configName}.yml") ); K8sConfig kubeConfig = K8sConfig.Load(configFile); var awsUser = kubeConfig.UserIdentities.FirstOrDefault( user => user.Name == "arn:aws:eks:us-east-1:123456789012:cluster/my-cluster"); Assert.Equal("aws", awsUser?.Config?.Exec?.Command); Assert.Equal(6, awsUser?.Config?.Exec?.Arguments?.Count); Assert.Equal(1, awsUser?.Config?.Exec?.EnvironmentVariables.Count); }
public KubeApiClient CreateClient() { return(KubeApiClient.Create(K8sConfig.Load().ToKubeClientOptions(null, "default"))); //if (WebHostEnvironment.IsDevelopment()) //{ // return KubeApiClient.Create(K8sConfig.Load().ToKubeClientOptions()); //} //else //{ // // Load from in-cluster configuration: // var config = KubernetesClientConfiguration.InClusterConfig(); // return new Kubernetes(config); //} }
public KnativePlatform(string configFile) { this.configFile = configFile; KubeClientOptions options; if (!string.IsNullOrEmpty(configFile)) { options = K8sConfig.Load(configFile).ToKubeClientOptions(defaultKubeNamespace: FUNCTIONS_NAMESPACE); } else { options = K8sConfig.Load().ToKubeClientOptions(defaultKubeNamespace: FUNCTIONS_NAMESPACE); } client = KubeApiClient.Create(options); }
public void CanLoadValidConfig(string configName) { FileInfo configFile = new FileInfo( Path.Combine("Configurations", $"{configName}.yml") ); K8sConfig kubeConfig = K8sConfig.Load(configFile); Assert.Equal("v1", kubeConfig.ApiVersion); Assert.Equal("Config", kubeConfig.Kind); Assert.Equal("docker-for-desktop", kubeConfig.CurrentContextName); Assert.Equal(5, kubeConfig.Contexts.Count); Assert.Equal(5, kubeConfig.Clusters.Count); Assert.Equal(6, kubeConfig.UserIdentities.Count); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddHostedService <SecretsWatcherHostedService>(); services.AddControllers(); var clientOptions = K8sConfig.Load(@"C:\Users\linjm\.kube\config").ToKubeClientOptions( defaultKubeNamespace: "default" ); services.AddSingleton <KubeClientOptions>(clientOptions); var providers = new ISecretsProvider[] { new SecretsProvider() }; services.AddSingleton <IEnumerable <ISecretsProvider> >(providers); }
protected override async Task ProcessRecordAsync(CancellationToken cancellationToken) { await base.ProcessRecordAsync(cancellationToken); string configPath = K8sConfig.Locate(); K8sConfig config = K8sConfig.Load(configPath); config.CurrentContextName = Context; ISerializer serializer = new SerializerBuilder().Build(); string yaml = serializer.Serialize(config); if (ShouldProcess(configPath, "update")) { using (var streamWriter = new StreamWriter(configPath)) { await streamWriter.WriteAsync(yaml); // Do not pass cancellationToken to not corrupt config file } } }
protected override async Task BeginProcessingAsync(CancellationToken cancellationToken) { await base.BeginProcessingAsync(cancellationToken); config = K8sConfig.Load(); KubeClientOptions clientOptions = config.ToKubeClientOptions( defaultKubeNamespace: "default" ); clientOptions.AllowInsecure = AllowInsecure; if (ApiEndPoint != null) { clientOptions.ApiEndPoint = ApiEndPoint; } WriteVerbose($"Using endpoint {clientOptions.ApiEndPoint}"); // clientOptions.LogHeaders = true; clientOptions.LogPayloads = LogPayloads; client = KubeApiClient.Create(clientOptions, LoggerFactory); }
/// <summary> /// The main program entry-point. /// </summary> /// <param name="commandLineArguments"> /// The program's command-line arguments. /// </param> /// <returns> /// The program exit-code. /// </returns> static async Task <int> Main(string[] commandLineArguments) { ProgramOptions options = ProgramOptions.Parse(commandLineArguments); if (options == null) { return(ExitCodes.InvalidArguments); } ILoggerFactory loggerFactory = ConfigureLogging(options); try { const string configMapName = "config-from-configmap"; const string configMapNamespace = "default"; KubeClientOptions clientOptions = K8sConfig.Load().ToKubeClientOptions(defaultKubeNamespace: configMapNamespace, loggerFactory: loggerFactory); if (options.Verbose) { clientOptions.LogPayloads = true; } KubeApiClient client = KubeApiClient.Create(clientOptions); Log.Information("Checking for existing ConfigMap..."); ConfigMapV1 configMap = await client.ConfigMapsV1().Get(configMapName, configMapNamespace); if (configMap != null) { Log.Information("Deleting existing ConfigMap..."); await client.ConfigMapsV1().Delete(configMapName); Log.Information("Existing ConfigMap deleted."); } Log.Information("Creating new ConfigMap..."); configMap = await client.ConfigMapsV1().Create(new ConfigMapV1 { Metadata = new ObjectMetaV1 { Name = configMapName, Namespace = configMapNamespace }, Data = { ["Key1"] = "One", ["Key2"] = "Two" } }); Log.Information("New ConfigMap created."); Log.Information("Building configuration..."); IConfiguration configuration = new ConfigurationBuilder() .AddKubeConfigMap(clientOptions, configMapName: "config-from-configmap", reloadOnChange: true ) .Build(); Log.Information("Configuration built."); Log.Information("Got configuration:"); Dump(configuration); Log.Information("Press enter to update ConfigMap..."); Console.ReadLine(); Log.Information("Registering callback for change-notifications..."); ManualResetEvent configurationChanged = new ManualResetEvent(false); // See ConfigurationExtensions class below. IDisposable reloadNotifications = configuration.OnReload(() => { Log.Information("Got changed configuration:"); Dump(configuration); configurationChanged.Set(); }); Log.Information("Change-notification callback registered."); using (configurationChanged) using (reloadNotifications) { Log.Information("Updating ConfigMap..."); configMap.Data["One"] = "1"; configMap.Data["Two"] = "2"; // Replace the entire Data dictionary (to modify only some of the data, you'll need to use an untyped JsonPatchDocument). await client.ConfigMapsV1().Update(configMapName, patch => { patch.Replace(patchConfigMap => patchConfigMap.Data, value: configMap.Data ); }); Log.Information("Updated ConfigMap."); Log.Information("Waiting for configuration change..."); configurationChanged.WaitOne(); Log.Information("Configuration changed."); } return(ExitCodes.Success); } catch (HttpRequestException <StatusV1> kubeError) { Log.Error(kubeError, "Kubernetes API error: {@Status}", kubeError.Response); return(ExitCodes.UnexpectedError); } catch (Exception unexpectedError) { Log.Error(unexpectedError, "Unexpected error."); return(ExitCodes.UnexpectedError); } }
/// <summary> /// The main program entry-point. /// </summary> /// <param name="commandLineArguments"> /// The program's command-line arguments. /// </param> /// <returns> /// The program exit-code. /// </returns> static async Task <int> Main(string[] commandLineArguments) { ProgramOptions options = ProgramOptions.Parse(commandLineArguments); if (options == null) { return(ExitCodes.InvalidArguments); } ILoggerFactory loggerFactory = ConfigureLogging(options); try { KubeClientOptions clientOptions = K8sConfig.Load().ToKubeClientOptions(defaultKubeNamespace: options.KubeNamespace); if (options.Verbose) { clientOptions.LogPayloads = true; } KubeApiClient client = KubeApiClient.Create(clientOptions, loggerFactory); Log.Information("Looking for existing Deployment {DeploymentName} in namespace {KubeNamespace}...", options.DeploymentName, options.KubeNamespace ); DeploymentV1 existingDeployment = await client.DeploymentsV1().Get(options.DeploymentName, options.KubeNamespace); if (existingDeployment != null) { Log.Error("Cannot continue - deployment {DeploymentName} in namespace {KubeNamespace} already exists.", options.DeploymentName, options.KubeNamespace ); return(ExitCodes.AlreadyExists); } Log.Information("Ok, Deployment does not exist yet - we're ready to go."); Log.Information("Creating Deployment {DeploymentName} in namespace {KubeNamespace}...", options.DeploymentName, options.KubeNamespace ); DeploymentV1 initialDeployment = await CreateInitialDeployment(client, options.DeploymentName, options.KubeNamespace); int?initialRevision = initialDeployment.GetRevision(); if (initialRevision == null) { Log.Error("Unable to determine initial revision of Deployment {DeploymentName} in namespace {KubeNamespace} (missing annotation).", options.DeploymentName, options.KubeNamespace ); return(ExitCodes.UnexpectedError); } Log.Information("Created Deployment {DeploymentName} in namespace {KubeNamespace} (revision {DeploymentRevision}).", options.DeploymentName, options.KubeNamespace, initialRevision ); Log.Information("Updating Deployment {DeploymentName} in namespace {KubeNamespace}...", options.DeploymentName, options.KubeNamespace ); DeploymentV1 updatedDeployment = await UpdateDeployment(client, initialDeployment); int?updatedRevision = updatedDeployment.GetRevision(); if (updatedRevision == null) { Log.Error("Unable to determine updated revision of Deployment {DeploymentName} in namespace {KubeNamespace} (missing annotation).", options.DeploymentName, options.KubeNamespace ); return(ExitCodes.UnexpectedError); } Log.Information("Updated Deployment {DeploymentName} in namespace {KubeNamespace} (revision {DeploymentRevision}).", options.DeploymentName, options.KubeNamespace, updatedRevision ); Log.Information("Searching for ReplicaSet that corresponds to revision {Revision} of {DeploymentName} in namespace {KubeNamespace}...", options.DeploymentName, options.KubeNamespace, initialRevision ); ReplicaSetV1 targetReplicaSet = await FindReplicaSetForRevision(client, updatedDeployment, initialRevision.Value); if (targetReplicaSet == null) { Log.Error("Cannot find ReplicaSet that corresponds to revision {Revision} of {DeploymentName} in namespace {KubeNamespace}...", options.DeploymentName, options.KubeNamespace, initialRevision ); return(ExitCodes.NotFound); } Log.Information("Found ReplicaSet {ReplicaSetName} in namespace {KubeNamespace}.", targetReplicaSet.Metadata.Name, targetReplicaSet.Metadata.Namespace ); Log.Information("Rolling Deployment {DeploymentName} in namespace {KubeNamespace} back to initial revision {DeploymentRevision}...", options.DeploymentName, options.KubeNamespace, initialRevision ); DeploymentV1 rolledBackDeployment = await RollbackDeployment(client, updatedDeployment, targetReplicaSet); Log.Information("Rollback initiated for Deployment {DeploymentName} in namespace {KubeNamespace} from revision {FromRevision} to {ToRevision} (new revision will be {NewRevision})...", options.DeploymentName, options.KubeNamespace, updatedRevision, initialRevision, rolledBackDeployment.GetRevision() ); return(ExitCodes.Success); } catch (HttpRequestException <StatusV1> kubeError) { Log.Error(kubeError, "Kubernetes API error: {@Status}", kubeError.Response); return(ExitCodes.UnexpectedError); } catch (Exception unexpectedError) { Log.Error(unexpectedError, "Unexpected error."); return(ExitCodes.UnexpectedError); } }
/// <summary> /// The main program entry-point. /// </summary> /// <param name="commandLineArguments"> /// The program's command-line arguments. /// </param> /// <returns> /// The program exit-code. /// </returns> static async Task <int> Main(string[] commandLineArguments) { ProgramOptions options = ProgramOptions.Parse(commandLineArguments); if (options == null) { return(ExitCodes.InvalidArguments); } ILoggerFactory loggerFactory = ConfigureLogging(options); try { KubeClientOptions clientOptions = K8sConfig.Load().ToKubeClientOptions(defaultKubeNamespace: options.KubeNamespace, loggerFactory: loggerFactory); if (options.Verbose) { clientOptions.LogPayloads = true; } JsonSerializerSettings serializerSettings = KubeResourceClient.SerializerSettings; serializerSettings.Formatting = Formatting.Indented; KubeApiClient client = KubeApiClient.Create(clientOptions); EventListV1 initialEvents = await client.EventsV1().List(); ActionBlock <EventV1> eventProcessor = CreateEventProcessor(client); Log.Information("Initial events:"); Log.Information("==============="); if (initialEvents.Items.Count > 0) { foreach (EventV1 initialEvent in initialEvents) { eventProcessor.Post(initialEvent); } } else { Log.Information("No initial events."); } Log.Information("==============="); IObservable <IResourceEventV1 <EventV1> > eventStream; if (initialEvents.Items.Count > 0) { EventV1 lastEvent = initialEvents.Items[initialEvents.Items.Count - 1]; eventStream = client.EventsV1().WatchAll(resourceVersion: lastEvent.InvolvedObject.ResourceVersion); } else { eventStream = client.EventsV1().WatchAll(); } IDisposable subscription = eventStream.Select(resourceEvent => resourceEvent.Resource).Subscribe( subsequentEvent => eventProcessor.Post(subsequentEvent), error => Log.Error(error, "Unexpected error while streaming events.") ); using (subscription) { Log.Information("Watching for new events (press enter to terminate)."); Console.ReadLine(); } Log.Information("Waiting for event processor to shut down..."); eventProcessor.Complete(); await eventProcessor.Completion; Log.Information("Event processor has shut down."); return(ExitCodes.Success); } catch (HttpRequestException <StatusV1> kubeError) { Log.Error(kubeError, "Kubernetes API error: {@Status}", kubeError.Response); return(ExitCodes.UnexpectedError); } catch (Exception unexpectedError) { Log.Error(unexpectedError, "Unexpected error."); return(ExitCodes.UnexpectedError); } }
/// <summary> /// The main program entry-point. /// </summary> /// <param name="commandLineArguments"> /// The program's command-line arguments. /// </param> /// <returns> /// The program exit-code. /// </returns> static async Task <int> Main(string[] commandLineArguments) { // Show help if no arguments are specified. bool showHelp = commandLineArguments.Length == 0; if (showHelp) { commandLineArguments = new[] { "--help" } } ; ProgramOptions options = ProgramOptions.Parse(commandLineArguments); if (options == null) { return(showHelp ? ExitCodes.Success : ExitCodes.InvalidArguments); } ILoggerFactory loggers = ConfigureLogging(options); try { KubeClientOptions clientOptions = K8sConfig.Load().ToKubeClientOptions( kubeContextName: options.KubeContext, defaultKubeNamespace: options.KubeNamespace ); using (KubeApiClient client = KubeApiClient.Create(clientOptions, loggers)) { Log.LogInformation("Finding target pod..."); PodV1 targetPod = await client.PodsV1().Get(options.PodName, kubeNamespace: options.KubeNamespace ); if (targetPod == null) { Log.LogError("Pod '{PodName}' not found in namespace '{KubeNamespace}' on cluster ({KubeContextName}).", options.PodName, options.KubeNamespace, options.KubeContext ); return(ExitCodes.NotFound); } if (!String.IsNullOrWhiteSpace(options.ContainerName)) { ContainerStatusV1 targetContainer = targetPod.Status.ContainerStatuses.Find( container => container.Name == options.ContainerName ); if (targetContainer == null) { Log.LogError("Container '{ContainerName}' not found in Pod '{PodName}' in namespace '{KubeNamespace}' on cluster ({KubeContextName}).", options.ContainerName, options.PodName, options.KubeNamespace, options.KubeContext ); return(ExitCodes.NotFound); } } else if (targetPod.Status.ContainerStatuses.Count > 1) { Log.LogError("Pod '{PodName}' in namespace '{KubeNamespace}' on cluster ({KubeContextName}) has more than one container. Please specify the name of the target container", options.PodName, options.KubeNamespace, options.KubeContext ); return(ExitCodes.InvalidArguments); } Log.LogDebug("Connecting..."); K8sMultiplexer multiplexer = await client.PodsV1().ExecAndConnect( podName: options.PodName, container: options.ContainerName, command: options.Command, kubeNamespace: options.KubeContext, stdin: true, stdout: true, stderr: true, tty: true // Required for interactivity ); Log.LogInformation("Connected."); Task stdInPump, stdOutPump, stdErrPump; using (multiplexer) using (CancellationTokenSource pumpCancellation = new CancellationTokenSource()) using (Stream localStdIn = Console.OpenStandardInput()) using (Stream remoteStdIn = multiplexer.GetStdIn()) using (Stream localStdOut = Console.OpenStandardOutput()) using (Stream remoteStdOut = multiplexer.GetStdOut()) using (Stream localStdErr = Console.OpenStandardError()) using (Stream remoteStdErr = multiplexer.GetStdErr()) { stdInPump = localStdIn.CopyToAsync(remoteStdIn, pumpCancellation.Token); stdOutPump = remoteStdOut.CopyToAsync(localStdOut, pumpCancellation.Token); stdErrPump = remoteStdErr.CopyToAsync(localStdErr, pumpCancellation.Token); await multiplexer.WhenConnectionClosed; // Terminate stream pumps. pumpCancellation.Cancel(); } Log.LogInformation("Connection closed."); Log.LogInformation("Done."); } return(ExitCodes.Success); } catch (Exception unexpectedError) { Log.LogError(unexpectedError.ToString()); Log.LogError(unexpectedError, "Unexpected error."); return(ExitCodes.UnexpectedError); } }
/// <summary> /// The main program entry-point. /// </summary> /// <param name="commandLineArguments"> /// The program's command-line arguments. /// </param> /// <returns> /// The program exit-code. /// </returns> static async Task <int> Main(string[] commandLineArguments) { ProgramOptions options = ProgramOptions.Parse(commandLineArguments); if (options == null) { return(ExitCodes.InvalidArguments); } ILoggerFactory loggerFactory = ConfigureLogging(options); try { const string configMapName = "config-from-configmap"; const string configMapNamespace = "default"; KubeClientOptions clientOptions = K8sConfig.Load().ToKubeClientOptions(defaultKubeNamespace: configMapNamespace); if (options.Verbose) { clientOptions.LogPayloads = true; } KubeApiClient client = KubeApiClient.Create(clientOptions, loggerFactory); Log.Information("Checking for existing ConfigMap..."); ConfigMapV1 configMap = await client.ConfigMapsV1().Get(configMapName, configMapNamespace); if (configMap != null) { Log.Information("Deleting existing ConfigMap..."); await client.ConfigMapsV1().Delete(configMapName); Log.Information("Existing ConfigMap deleted."); } Log.Information("Creating new ConfigMap..."); configMap = await client.ConfigMapsV1().Create(new ConfigMapV1 { Metadata = new ObjectMetaV1 { Name = configMapName, Namespace = configMapNamespace }, Data = new Dictionary <string, string> { ["Key1"] = "One", ["Key2"] = "Two" } }); Log.Information("New ConfigMap created."); Log.Information("Building configuration..."); IConfiguration configuration = new ConfigurationBuilder() .AddKubeConfigMap(clientOptions, configMapName: "config-from-configmap", reloadOnChange: true ) .Build(); Log.Information("Configuration built."); configuration.GetReloadToken().RegisterChangeCallback(_ => { Log.Information("Got changed configuration:"); foreach (var item in configuration.AsEnumerable()) { Log.Information("\t'{Key}' = '{Value}'", item.Key, item.Value); } }, state: null); Log.Information("Got configuration:"); foreach (var item in configuration.AsEnumerable()) { Log.Information("\t'{Key}' = '{Value}'", item.Key, item.Value); } Log.Information("Press enter to update ConfigMap..."); Console.ReadLine(); Log.Information("Updating ConfigMap..."); configMap.Data["One"] = "1"; configMap.Data["Two"] = "2"; // Replace the entire Data dictionary (otherwise, use an untyped JsonPatchDocument). await client.ConfigMapsV1().Update(configMapName, patch => { patch.Replace(patchConfigMap => patchConfigMap.Data, value: configMap.Data ); }); Log.Information("Updated ConfigMap."); Log.Information("Waiting for configuration change; press enter to terminate."); Console.ReadLine(); return(ExitCodes.Success); } catch (HttpRequestException <StatusV1> kubeError) { Log.Error(kubeError, "Kubernetes API error: {@Status}", kubeError.Response); return(ExitCodes.UnexpectedError); } catch (Exception unexpectedError) { Log.Error(unexpectedError, "Unexpected error."); return(ExitCodes.UnexpectedError); } }
public string[] GetValidValues() { return(K8sConfig.Load().Contexts.ConvertAll(context => context.Name).ToArray()); }