Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/november pack #7

Merged
merged 2 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/SmoothSailing.MsSql/charts/mssql/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ containers:
podAnnotations: {}

service:
type: LoadBalancer
type: ClusterIP
port: 1433
50 changes: 43 additions & 7 deletions src/SmoothSailing/ChartInstaller.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace SmoothSailing;

public class ChartInstaller
{
public static IProcessOutputWriter DefaultOutputWriter { get; set; } = new ConsoleProcessOutputWriter();

private readonly IProcessLauncher _processLauncher;
private readonly ProcessLauncher _processLauncher;
private readonly IProcessOutputWriter _processOutputWriter;

public ChartInstaller(IProcessOutputWriter? processOutputWriter = null)
{
_processLauncher = new ProcessLauncher(processOutputWriter ?? DefaultOutputWriter);
this._processOutputWriter = processOutputWriter ?? DefaultOutputWriter;
_processLauncher = new ProcessLauncher(_processOutputWriter);
}

/// <summary>
Expand All @@ -42,18 +46,50 @@ public async Task<Release> Install(IChart chart, string releaseName, object? ove
listCommandParameters.ApplyContextInfo(context);


var executeToEnd = await _processLauncher.ExecuteToEnd("helm", $"list {listCommandParameters.Build()}", default);
var executeToEnd = await _processLauncher.ExecuteToEnd("helm", $"list {listCommandParameters.Build()}", mute: false, default);
if (executeToEnd != "[]")
{
// INFO: try to uninstall previous installation
var uninstallParameters = new HelmCommandParameterBuilder(new List<string>
{
"--wait"
});

uninstallParameters.ApplyContextInfo(context );

await _processLauncher.ExecuteToEnd("helm", $"uninstall {releaseName} {uninstallParameters.Build()}", default);
await _processLauncher.ExecuteToEnd("helm", $"uninstall {releaseName} {uninstallParameters.Build()}", mute: false, default);
}
else
{
// INFO: Sometimes, for unknown reasons, helm uninstall release but do not update info about uninstall state
// This info is kept in secrets. Removing this specific secret should fix things up
try
{
var getSecretsParameters = new KubectlCommandParameterBuilder(new List<string>()
{
"-A",
"-o json"
});
getSecretsParameters.ApplyContextInfo(context);
var getSecretsResults = await _processLauncher.ExecuteToEnd("kubectl", $"get secrets {getSecretsParameters.Build()}", mute: true,default);
if (JObject.Parse(getSecretsResults) is { } secrets)
{
var result = secrets.SelectTokens($"$.items[?(@.metadata.labels.name == '{releaseName}' && @.kind == 'Secret' && @.metadata.labels.owner == 'helm')].metadata.name").FirstOrDefault();
if (result is JValue {Value: string secretName} && string.IsNullOrWhiteSpace(secretName) == false && secretName.StartsWith("sh.helm.release."))
{
_processOutputWriter.Write($"Detected dangling release by discovering secret '{secretName}");
var deleteSecretParameters = new KubectlCommandParameterBuilder(new List<string>());
deleteSecretParameters.ApplyContextInfo(context);
await _processLauncher.ExecuteToEnd("kubectl", $"delete secrets {secretName} {deleteSecretParameters.Build()}", mute: false,default);
}
}
}
catch (Exception e)
{
_processOutputWriter.WriteError(e.Message);
}
}



var installParameters = new HelmCommandParameterBuilder(new List<string>
{
Expand All @@ -80,7 +116,7 @@ public async Task<Release> Install(IChart chart, string releaseName, object? ove
installParameters.Add($"-f \"{overridesPath}\"");
}

await _processLauncher.ExecuteToEnd("helm", $"upgrade {releaseName} {installParameters.Build()}", default);
await _processLauncher.ExecuteToEnd("helm", $"upgrade {releaseName} {installParameters.Build()}", mute: false, default);
return new Release(releaseName, _processLauncher, context);
}
}
}
36 changes: 36 additions & 0 deletions src/SmoothSailing/HelmCommandParameterBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,39 @@ public void ApplyContextInfo(KubernetesContext? context)

public string Build() => string.Join(" ", _parameters);
}


internal class KubectlCommandParameterBuilder
{
internal readonly List<string> _parameters;

public KubectlCommandParameterBuilder(IReadOnlyList<string>? parameters = null)
{
_parameters = parameters?.ToList() ?? new List<string>();
}

public void Add(string parameter) => _parameters.Add(parameter);

public void ApplyContextInfo(KubernetesContext? context)
{
if (context == null)
return;

if (!string.IsNullOrEmpty(context.APIServer))
_parameters.Add($"--server \"{context.APIServer}\"");

if (!string.IsNullOrEmpty(context.Token))
_parameters.Add($"--token \"{context.Token}\"");

if (!string.IsNullOrEmpty(context.KubeConfig))
_parameters.Add($"--kubeconfig \"{context.KubeConfig}\"");

if (!string.IsNullOrEmpty(context.Namespace))
_parameters.Add($"--namespace \"{context.Namespace}\"");

if (context.InsecureSkipTLSVerify.HasValue && context.InsecureSkipTLSVerify.Value)
_parameters.Add("--insecure-skip-tls-verify");
}

public string Build() => string.Join(" ", _parameters);
}
9 changes: 0 additions & 9 deletions src/SmoothSailing/IProcessLauncher.cs

This file was deleted.

9 changes: 6 additions & 3 deletions src/SmoothSailing/ProcessLauncher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace SmoothSailing
{
internal class ProcessLauncher : IProcessLauncher
internal class ProcessLauncher
{
private readonly IProcessOutputWriter _processOutputWriter;

Expand All @@ -18,7 +18,7 @@ public ProcessLauncher(IProcessOutputWriter processOutputWriter)
_processOutputWriter = processOutputWriter;
}

public async IAsyncEnumerable<string> Execute(string command, string parameters, [EnumeratorCancellation] CancellationToken token)
public async IAsyncEnumerable<string> Execute(string command, string parameters, bool mute, [EnumeratorCancellation] CancellationToken token)
{
var channel = Channel.CreateUnbounded<string>();

Expand All @@ -34,7 +34,10 @@ await Cli.Wrap(command)
.WithStandardOutputPipe(PipeTarget.ToDelegate(async s =>
{
await writer.WriteAsync(s, default);
_processOutputWriter.Write(s);
if (mute == false)
{
_processOutputWriter.Write(s);
}
}))
.WithStandardErrorPipe(PipeTarget.ToDelegate(async s =>
{
Expand Down
4 changes: 2 additions & 2 deletions src/SmoothSailing/ProcessLauncherExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ namespace SmoothSailing;

internal static class ProcessLauncherExtensions
{
public static async Task<string> ExecuteToEnd(this IProcessLauncher @this, string command, string parameters, CancellationToken token)
public static async Task<string> ExecuteToEnd(this ProcessLauncher @this, string command, string parameters, bool mute, CancellationToken token)
{
var outputBuilder = new StringBuilder();
await foreach (var line in @this.Execute(command, parameters, token))
await foreach (var line in @this.Execute(command, parameters, mute, token))
{
outputBuilder.Append(line);
}
Expand Down
10 changes: 5 additions & 5 deletions src/SmoothSailing/Release.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ namespace SmoothSailing;
public class Release : IAsyncDisposable
{
public string DeploymentName { get; }
private readonly IProcessLauncher _processExecutor;
private readonly ProcessLauncher _processExecutor;
private readonly KubernetesContext? _kubernetesContext;
private readonly List<(Task, CancellationTokenSource)> _portForwards = new();

internal Release(string deploymentName, IProcessLauncher processExecutor, KubernetesContext? kubernetesContext)
internal Release(string deploymentName, ProcessLauncher processExecutor, KubernetesContext? kubernetesContext)
{
DeploymentName = deploymentName;
_processExecutor = processExecutor;
Expand All @@ -30,9 +30,9 @@ public async Task<int> StartPortForwardForPod(string serviceName, int servicePor
private async Task<int> StartPortForwardFor(string elementType, string elementName, int servicePort, int? localPort)
{
var cancellationTokenSource = new CancellationTokenSource();
var portForwardParameters = new HelmCommandParameterBuilder();
var portForwardParameters = new KubectlCommandParameterBuilder();
portForwardParameters.ApplyContextInfo(_kubernetesContext);
var asyncEnumerable = _processExecutor.Execute("kubectl", $"port-forward {elementType}/{elementName} {localPort}:{servicePort} {portForwardParameters.Build()}", cancellationTokenSource.Token);
var asyncEnumerable = _processExecutor.Execute("kubectl", $"port-forward {elementType}/{elementName} {localPort}:{servicePort} {portForwardParameters.Build()}", mute:false, cancellationTokenSource.Token);

var enumerator = asyncEnumerable.GetAsyncEnumerator(default);
await enumerator.MoveNextAsync();
Expand Down Expand Up @@ -84,6 +84,6 @@ public async ValueTask DisposeAsync()
var uninstallParameters = new HelmCommandParameterBuilder();
uninstallParameters.ApplyContextInfo(_kubernetesContext);
uninstallParameters.Add("--wait");
await _processExecutor.ExecuteToEnd("helm", $"uninstall {DeploymentName} {uninstallParameters.Build()}", default);
await _processExecutor.ExecuteToEnd("helm", $"uninstall {DeploymentName} {uninstallParameters.Build()}", mute: false, default);
}
}
Loading