Files
123123/ZA.CoreService.ESBCertificateManager/Services/SonicBinRestartExecutor.cs
T

151 lines
6.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Diagnostics;
using System.Text;
using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
/// <summary>
/// Neustart über die offiziellen Sonic-Bin-Scripts (laut Doku):
/// SonicHome\bin\stopcontainer.bat Domain.Container
/// SonicHome\bin\startcontainer.bat Domain.Container
/// Die Scripts setzen selbst JAVA_HOME kein separates System-Java nötig.
/// </summary>
public sealed class SonicBinRestartExecutor
{
private readonly SonicConnection _connection;
public SonicBinRestartExecutor(SonicConnection connection)
{
_connection = connection;
}
public (bool Ok, string? Error, string? Detail) Probe()
{
string sonicHome = _connection.SonicHome?.Trim() ?? string.Empty;
if (string.IsNullOrWhiteSpace(sonicHome))
{
return (false, "SonicHome ist leer in appsettings setzen.", null);
}
if (!Directory.Exists(sonicHome))
{
return (false, $"SonicHome existiert nicht: '{sonicHome}'", null);
}
string stop = Path.Combine(sonicHome, "bin", "stopcontainer.bat");
string start = Path.Combine(sonicHome, "bin", "startcontainer.bat");
if (!File.Exists(stop) || !File.Exists(start))
{
return (false,
$"stopcontainer.bat/startcontainer.bat fehlen unter '{Path.Combine(sonicHome, "bin")}'.",
$"stop={File.Exists(stop)}; start={File.Exists(start)}");
}
return (true, null, $"SonicHome={sonicHome}");
}
public async Task<(bool Success, string Status, string? Detail)> RestartAsync(
string containerName,
CancellationToken cancellationToken = default)
{
(bool probeOk, string? probeError, string? probeDetail) = Probe();
if (!probeOk)
{
return (false, "Neustart fehlgeschlagen (SonicBin)",
$"{probeError}\n{probeDetail}");
}
string sonicHome = _connection.SonicHome.Trim();
string bin = Path.Combine(sonicHome, "bin");
string stopBat = Path.Combine(bin, "stopcontainer.bat");
string startBat = Path.Combine(bin, "startcontainer.bat");
string shortName = containerName.Contains('.')
? containerName[(containerName.IndexOf('.') + 1)..]
: containerName;
string fullName = containerName.Contains('.')
? containerName
: $"{_connection.DomainName}.{containerName}";
StringBuilder log = new();
log.AppendLine($"SonicHome={sonicHome}");
log.AppendLine($"Container={fullName} (kurz={shortName})");
(bool stopOk, string stopOut, string stopErr, int stopCode) =
await RunBatAsync(stopBat, fullName, bin, cancellationToken);
log.AppendLine($"STOP ExitCode={stopCode}");
if (stopOut.Length > 0) log.AppendLine("STOP out: " + Truncate(stopOut));
if (stopErr.Length > 0) log.AppendLine("STOP err: " + Truncate(stopErr));
// stopcontainer kann ExitCode!=0 liefern wenn Container schon down trotzdem starten
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
(bool startOk, string startOut, string startErr, int startCode) =
await RunBatAsync(startBat, fullName, bin, cancellationToken);
log.AppendLine($"START ExitCode={startCode}");
if (startOut.Length > 0) log.AppendLine("START out: " + Truncate(startOut));
if (startErr.Length > 0) log.AppendLine("START err: " + Truncate(startErr));
if (!startOk || startCode != 0)
{
// Fallback: Kurzname ohne Domain
if (!string.Equals(shortName, fullName, StringComparison.OrdinalIgnoreCase))
{
log.AppendLine($"Retry START mit Kurzname '{shortName}'…");
(startOk, startOut, startErr, startCode) =
await RunBatAsync(startBat, shortName, bin, cancellationToken);
log.AppendLine($"START(short) ExitCode={startCode}");
if (startOut.Length > 0) log.AppendLine("START out: " + Truncate(startOut));
if (startErr.Length > 0) log.AppendLine("START err: " + Truncate(startErr));
}
}
await Task.Delay(
TimeSpan.FromSeconds(Math.Clamp(_connection.PostRestartDelaySeconds, 0, 120)),
cancellationToken);
if (startCode != 0)
{
return (false, "Neustart fehlgeschlagen (SonicBin)",
$"startcontainer ExitCode={startCode} (stop ExitCode={stopCode}).\n{log}");
}
return (true, $"Container '{fullName}' neugestartet (SonicBin)", log.ToString());
}
private static async Task<(bool Started, string StdOut, string StdErr, int ExitCode)> RunBatAsync(
string batPath,
string argument,
string workingDirectory,
CancellationToken cancellationToken)
{
ProcessStartInfo psi = new()
{
FileName = "cmd.exe",
Arguments = $"/c \"\"{batPath}\" \"{argument}\"\"",
WorkingDirectory = workingDirectory,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
};
using Process process = new() { StartInfo = psi };
if (!process.Start())
{
return (false, string.Empty, "cmd.exe konnte nicht gestartet werden.", -1);
}
Task<string> stdoutTask = process.StandardOutput.ReadToEndAsync(cancellationToken);
Task<string> stderrTask = process.StandardError.ReadToEndAsync(cancellationToken);
await process.WaitForExitAsync(cancellationToken);
return (true, (await stdoutTask).Trim(), (await stderrTask).Trim(), process.ExitCode);
}
private static string Truncate(string value, int max = 500)
=> value.Length <= max ? value : value[..max] + "…";
}