Fix restart without system Java via Sonic stop/startcontainer.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
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] + "…";
|
||||
}
|
||||
Reference in New Issue
Block a user