Fix restart without system Java via Sonic stop/startcontainer.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-24 09:16:11 +02:00
co-authored by Cursor
parent d1ef63f3f7
commit fe61bd087a
6 changed files with 289 additions and 52 deletions
@@ -95,18 +95,49 @@ public sealed class SonicManagementClient : IDisposable
if (UsesMfApi)
{
(bool ok, string? error) = await _mfApi!.TestConnectionAsync(cancellationToken);
string modeLabel =
$"MfApi {_connection.ConnectionUrl} Domain={_connection.DomainName}";
return (ok, error, ok ? modeLabel : null);
if (ok)
{
return (true, null,
$"MfApi {_connection.ConnectionUrl} Domain={_connection.DomainName}");
}
// Ohne lokales Java: Domain-Manager-TCP + KnownContainers reichen für Discovery.
bool javaMissing = error?.Contains("Java nicht gefunden", StringComparison.OrdinalIgnoreCase) == true;
if (javaMissing)
{
SonicBinRestartExecutor bin = new(_connection);
(bool binOk, _, string? binDetail) = bin.Probe();
if (binOk)
{
return (true, null,
$"SonicBin Fallback (kein Java für MfApi) {binDetail}; {_connection.ConnectionUrl}");
}
if (_connection.KnownContainers.Count > 0
|| await IsTcpReachableAsync(_connection.ConnectionUrl, cancellationToken))
{
return (true, null,
$"MfApi ohne Java KnownContainers/TCP; Hinweis: {Truncate(error ?? string.Empty, 180)}");
}
}
return (false, error, null);
}
if (UsesScripts)
{
if (Mode == SonicManagementMode.LocalCmd)
{
(bool binOk, string? binError, string? binDetail) = new SonicBinRestartExecutor(_connection).Probe();
return binOk
? (true, null, $"LocalCmd/SonicBin {binDetail}")
: (false, binError, null);
}
(bool ok, string? error) = await _scriptRunner!.TestConnectionAsync(cancellationToken);
string modeLabel = Mode == SonicManagementMode.LocalCmd
? $"LocalCmd (SonicHome={_connection.SonicHome})"
: $"WinRM auf {ExtractHost(_connection.ConnectionUrl)}:{_connection.WinRmPort}";
return (ok, error, ok ? modeLabel : null);
return ok
? (true, null, $"WinRM auf {ExtractHost(_connection.ConnectionUrl)}:{_connection.WinRmPort}")
: (false, error, null);
}
try
@@ -169,6 +200,13 @@ public sealed class SonicManagementClient : IDisposable
if (UsesScripts)
{
// LocalCmd / WinRm: bevorzugter Doku-Weg über die .bat-Dateien (ohne extra Java-Suche).
if (Mode == SonicManagementMode.LocalCmd)
{
return await new SonicBinRestartExecutor(_connection)
.RestartAsync(containerName, cancellationToken);
}
return await RestartViaScriptAsync(containerName, cancellationToken);
}
@@ -260,22 +298,60 @@ public sealed class SonicManagementClient : IDisposable
(bool ok, string? output, string? error) =
await _mfApi!.RestartAsync(containerName, cancellationToken);
if (!ok)
if (ok)
{
return (false, "Neustart fehlgeschlagen (MfApi)",
$"IAgentProxy.restart für '{containerName}' (Domain '{_connection.DomainName}') " +
$"über {_connection.ConnectionUrl} fehlgeschlagen.\n" +
$"Fehler: {error}\nAusgabe: {output}\n" +
"Voraussetzungen: Domain Manager erreichbar, SMC-Logins korrekt, " +
"JRE (JavaHome/SonicHome\\jre/JAVA_HOME) + Sonic-Client-JARs (SonicHome\\lib), Container online.");
await Task.Delay(
TimeSpan.FromSeconds(Math.Clamp(_connection.PostRestartDelaySeconds, 0, 120)),
cancellationToken);
return (true, $"Container '{containerName}' neugestartet (MfApi)",
$"Domain={_connection.DomainName}; ConnectionUrl={_connection.ConnectionUrl}\n{output}");
}
await Task.Delay(
TimeSpan.FromSeconds(Math.Clamp(_connection.PostRestartDelaySeconds, 0, 120)),
cancellationToken);
// Kein Java / keine Client-JARs → offizieller Doku-Weg über stop/startcontainer.bat
bool softFail = error?.Contains("Java nicht gefunden", StringComparison.OrdinalIgnoreCase) == true
|| error?.Contains("Client-JARs", StringComparison.OrdinalIgnoreCase) == true
|| error?.Contains("lib", StringComparison.OrdinalIgnoreCase) == true;
return (true, $"Container '{containerName}' neugestartet (MfApi)",
$"Domain={_connection.DomainName}; ConnectionUrl={_connection.ConnectionUrl}\n{output}");
if (softFail)
{
SonicBinRestartExecutor bin = new(_connection);
(bool binOk, string binStatus, string? binDetail) =
await bin.RestartAsync(containerName, cancellationToken);
if (binOk)
{
return (true, binStatus,
$"MfApi nicht nutzbar ({Truncate(error ?? string.Empty, 160)}) Fallback SonicBin:\n{binDetail}");
}
return (false, "Neustart fehlgeschlagen (MfApi→SonicBin)",
$"MfApi: {error}\n\nSonicBin-Fallback: {binDetail}\n" +
$"SonicHome='{_connection.SonicHome}' muss stopcontainer.bat enthalten.");
}
return (false, "Neustart fehlgeschlagen (MfApi)",
$"IAgentProxy.restart für '{containerName}' (Domain '{_connection.DomainName}') " +
$"über {_connection.ConnectionUrl} fehlgeschlagen.\n" +
$"Fehler: {error}\nAusgabe: {output}");
}
private static async Task<bool> IsTcpReachableAsync(string connectionUrl, CancellationToken cancellationToken)
{
try
{
Uri uri = new(connectionUrl);
string host = uri.Host;
int port = uri.Port > 0 ? uri.Port : 2506;
using System.Net.Sockets.TcpClient tcp = new();
using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
cts.CancelAfter(TimeSpan.FromSeconds(5));
await tcp.ConnectAsync(host, port, cts.Token);
return true;
}
catch
{
return false;
}
}
private static SonicConnection CloneAsLocalCmd(SonicConnection source)