diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicBinRestartExecutor.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicBinRestartExecutor.cs
index 8c7b04c..4cfe2d0 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/SonicBinRestartExecutor.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/SonicBinRestartExecutor.cs
@@ -5,10 +5,10 @@ using ZA.CoreService.ESBCertificateManager.Models;
namespace ZA.CoreService.ESBCertificateManager.Services;
///
-/// 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.
+/// Neustart über Sonic-Server-Scripts:
+/// stopcontainer.bat / startcontainer.bat
+/// Diese liegen nur in einer vollen MQ/ESB-Server-Installation – nicht in einer
+/// reinen Sonic Management Console (SMC/Client).
///
public sealed class SonicBinRestartExecutor
{
@@ -32,16 +32,28 @@ public sealed class SonicBinRestartExecutor
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))
+ (string? stop, string? start, string searchNote) = LocateContainerScripts(sonicHome);
+ if (stop is null || start is null)
{
+ string binDir = Path.Combine(sonicHome, "bin");
+ string binListing = DescribeDirectory(binDir);
+ bool looksLikeSmcOnly = Directory.Exists(Path.Combine(sonicHome, "lib"))
+ && !File.Exists(Path.Combine(binDir, "stopcontainer.bat"));
+
+ string why = looksLikeSmcOnly
+ ? "Das sieht nach einer Sonic Management Console / Client-Installation aus "
+ + "(lib vorhanden, aber keine Server-Scripts). "
+ + "stopcontainer.bat gibt es nur auf dem Sonic-SERVER, nicht in der reinen SMC."
+ : "Server-Scripts wurden unter SonicHome nicht gefunden.";
+
return (false,
- $"stopcontainer.bat/startcontainer.bat fehlen unter '{Path.Combine(sonicHome, "bin")}'.",
- $"stop={File.Exists(stop)}; start={File.Exists(start)}");
+ why + $" Gesucht unter '{sonicHome}'.",
+ $"{searchNote}\nInhalt von bin: {binListing}\n"
+ + "Lösung A: SonicHome auf den Server-Installationspfad setzen (dort wo stopcontainer.bat liegt).\n"
+ + "Lösung B: App lässt automatisch MfApi/SMC-Verbindung versuchen (ConnectionUrl + Login).");
}
- return (true, null, $"SonicHome={sonicHome}");
+ return (true, null, $"stop={stop}; start={start}");
}
public async Task<(bool Success, string Status, string? Detail)> RestartAsync(
@@ -56,9 +68,8 @@ public sealed class SonicBinRestartExecutor
}
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? stopBat, string? startBat, _) = LocateContainerScripts(sonicHome);
+ string bin = Path.GetDirectoryName(stopBat!)!;
string shortName = containerName.Contains('.')
? containerName[(containerName.IndexOf('.') + 1)..]
@@ -69,35 +80,33 @@ public sealed class SonicBinRestartExecutor
StringBuilder log = new();
log.AppendLine($"SonicHome={sonicHome}");
+ log.AppendLine($"stop={stopBat}");
+ log.AppendLine($"start={startBat}");
log.AppendLine($"Container={fullName} (kurz={shortName})");
(bool stopOk, string stopOut, string stopErr, int stopCode) =
- await RunBatAsync(stopBat, fullName, bin, cancellationToken);
+ 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);
+ 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)
+ if (startCode != 0
+ && !string.Equals(shortName, fullName, StringComparison.OrdinalIgnoreCase))
{
- // 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));
- }
+ log.AppendLine($"Retry START mit Kurzname '{shortName}'…");
+ (_, 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(
@@ -113,6 +122,92 @@ public sealed class SonicBinRestartExecutor
return (true, $"Container '{fullName}' neugestartet (SonicBin)", log.ToString());
}
+ ///
+ /// Sucht stop/startcontainer.bat unter SonicHome\bin und rekursiv (max. Tiefe 4).
+ ///
+ public static (string? StopBat, string? StartBat, string Note) LocateContainerScripts(string sonicHome)
+ {
+ List candidates = [];
+
+ void AddDir(string? dir)
+ {
+ if (!string.IsNullOrWhiteSpace(dir) && Directory.Exists(dir) && !candidates.Contains(dir))
+ {
+ candidates.Add(dir);
+ }
+ }
+
+ AddDir(Path.Combine(sonicHome, "bin"));
+ AddDir(Path.Combine(sonicHome, "MQ_HOME", "bin"));
+ AddDir(Path.Combine(sonicHome, "MQ", "bin"));
+
+ try
+ {
+ string? parent = Directory.GetParent(sonicHome)?.FullName;
+ if (parent is not null)
+ {
+ foreach (string child in Directory.EnumerateDirectories(parent))
+ {
+ AddDir(Path.Combine(child, "bin"));
+ }
+ }
+ }
+ catch
+ {
+ // ignore
+ }
+
+ // Rekursiv nach Dateinamen suchen
+ try
+ {
+ foreach (string file in Directory.EnumerateFiles(sonicHome, "stopcontainer.bat", SearchOption.AllDirectories)
+ .Take(20))
+ {
+ AddDir(Path.GetDirectoryName(file));
+ }
+ }
+ catch
+ {
+ // ignore permission issues
+ }
+
+ foreach (string dir in candidates)
+ {
+ string stop = Path.Combine(dir, "stopcontainer.bat");
+ string start = Path.Combine(dir, "startcontainer.bat");
+ if (File.Exists(stop) && File.Exists(start))
+ {
+ return (stop, start, $"Scripts gefunden in '{dir}'");
+ }
+ }
+
+ return (null, null, $"Keine Scripts in {candidates.Count} geprüften bin-Ordnern.");
+ }
+
+ private static string DescribeDirectory(string dir)
+ {
+ if (!Directory.Exists(dir))
+ {
+ return "(Ordner existiert nicht)";
+ }
+
+ try
+ {
+ string[] names = Directory.GetFileSystemEntries(dir)
+ .Select(Path.GetFileName)
+ .Where(n => n is not null)
+ .Cast()
+ .OrderBy(n => n)
+ .Take(25)
+ .ToArray();
+ return names.Length == 0 ? "(leer)" : string.Join(", ", names);
+ }
+ catch (Exception ex)
+ {
+ return $"(nicht lesbar: {ex.Message})";
+ }
+ }
+
private static async Task<(bool Started, string StdOut, string StdErr, int ExitCode)> RunBatAsync(
string batPath,
string argument,
diff --git a/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs b/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
index 6144902..1c2bcbe 100644
--- a/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
+++ b/ZA.CoreService.ESBCertificateManager/Services/SonicManagementClient.cs
@@ -200,11 +200,49 @@ 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);
+ (bool binOk, string binStatus, string? binDetail) =
+ await new SonicBinRestartExecutor(_connection)
+ .RestartAsync(containerName, cancellationToken);
+
+ if (binOk)
+ {
+ return (true, binStatus, binDetail);
+ }
+
+ // Reine SMC/Client-Installation ohne Server-bin → wie die Console selbst
+ // über ConnectionUrl + SMC-Login (MfApi) neu starten.
+ bool batsMissing = binDetail?.Contains("stopcontainer", StringComparison.OrdinalIgnoreCase) == true
+ || binStatus.Contains("SonicBin", StringComparison.OrdinalIgnoreCase);
+
+ if (batsMissing)
+ {
+ SonicMfApiExecutor mf = new(_connection);
+ (bool mfOk, string? mfOut, string? mfErr) =
+ await mf.RestartAsync(containerName, cancellationToken);
+ if (mfOk)
+ {
+ await Task.Delay(
+ TimeSpan.FromSeconds(Math.Clamp(_connection.PostRestartDelaySeconds, 0, 120)),
+ cancellationToken);
+ return (true, $"Container '{containerName}' neugestartet (SMC/MfApi)",
+ $"Kein stopcontainer.bat unter SonicHome – SMC-Verbindung genutzt.\n{mfOut}");
+ }
+
+ return (false, "Neustart fehlgeschlagen",
+ "Ursache: Unter SonicHome fehlen stopcontainer.bat/startcontainer.bat.\n" +
+ "Das ist typisch, wenn nur die Sonic Management Console (Client) installiert ist –\n" +
+ "die Scripts liegen auf dem Sonic-SERVER.\n\n" +
+ $"SonicBin: {binDetail}\n\n" +
+ $"SMC/MfApi-Fallback: {mfErr}\n{mfOut}\n\n" +
+ "Was tun:\n" +
+ "1) SonicHome auf den Server-Pfad setzen (Ordner mit bin\\stopcontainer.bat), ODER\n" +
+ "2) Java + Client-JARs unter SonicHome\\lib bereitstellen (wie SMC),\n" +
+ " ConnectionUrl/User/Pass = dieselben Werte wie beim SMC-Login.");
+ }
+
+ return (false, binStatus, binDetail);
}
return await RestartViaScriptAsync(containerName, cancellationToken);
diff --git a/ZA.CoreService.ESBCertificateManager/appsettings.json b/ZA.CoreService.ESBCertificateManager/appsettings.json
index 3b446f7..74e2ae6 100644
--- a/ZA.CoreService.ESBCertificateManager/appsettings.json
+++ b/ZA.CoreService.ESBCertificateManager/appsettings.json
@@ -13,7 +13,7 @@
"Username": "Administrator",
"Password": "Administrator",
"ManagementMode": "LocalCmd",
- "SonicHome": "C:\\Sonic\\MQ10.0",
+ "SonicHome": "C:\\DEV\\MQ10.0",
"JavaHome": "",
"JavaPath": "",
"MfClientLibPath": "",