Remove XApi, WinRM, LocalCmd, HTTP API, TLS probe, SQL deploy model, and deploy UI. Co-authored-by: Cursor <cursoragent@cursor.com>
109 lines
3.7 KiB
C#
109 lines
3.7 KiB
C#
using ZA.CoreService.ESBCertificateManager.Models;
|
||
|
||
namespace ZA.CoreService.ESBCertificateManager.Services;
|
||
|
||
/// <summary>
|
||
/// Dünne Fassade über die Sonic MfApi (wie SMC-Neustart).
|
||
/// </summary>
|
||
public sealed class SonicManagementClient : IDisposable
|
||
{
|
||
private readonly SonicConnection _connection;
|
||
private readonly SonicMfApiExecutor _mfApi;
|
||
|
||
public SonicManagementClient(SonicConnection connection)
|
||
{
|
||
_connection = connection;
|
||
_mfApi = new SonicMfApiExecutor(connection);
|
||
}
|
||
|
||
public async Task<(bool Reachable, string? Error, string? Detail)> CheckConnectionAsync(
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
(bool ok, string? error) = await _mfApi.TestConnectionAsync(cancellationToken);
|
||
if (ok)
|
||
{
|
||
return (true, null, $"MfApi {_connection.ConnectionUrl} Domain={_connection.DomainName}");
|
||
}
|
||
|
||
// Soft-Fallback: KnownContainers + TCP reichen für Discovery
|
||
if (_connection.KnownContainers.Count > 0
|
||
&& await IsTcpReachableAsync(_connection.ConnectionUrl, cancellationToken))
|
||
{
|
||
return (true, null,
|
||
$"MfApi-Ping fehlgeschlagen, KnownContainers/TCP ok. Hinweis: {Truncate(error)}");
|
||
}
|
||
|
||
return (false, error ?? "MfApi-Verbindung fehlgeschlagen", null);
|
||
}
|
||
|
||
public async Task<(bool Success, IReadOnlyList<string> ContainerNames, string? Error)> GetContainersAsync(
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
(bool ok, IReadOnlyList<string> names, string? error) =
|
||
await _mfApi.ListContainersAsync(cancellationToken);
|
||
|
||
if (ok && names.Count > 0)
|
||
{
|
||
return (true, names, null);
|
||
}
|
||
|
||
if (_connection.KnownContainers.Count > 0)
|
||
{
|
||
return (true, _connection.KnownContainers,
|
||
ok ? null : $"Liste leer/fehlerhaft – KnownContainers. {error}");
|
||
}
|
||
|
||
return (false, [], error ?? "Keine Container gefunden.");
|
||
}
|
||
|
||
public async Task<(bool Success, string Status, string? Detail)> RestartContainerAsync(
|
||
string containerName,
|
||
CancellationToken cancellationToken = default)
|
||
{
|
||
(bool ok, string? output, string? error) =
|
||
await _mfApi.RestartAsync(containerName, cancellationToken);
|
||
|
||
if (ok)
|
||
{
|
||
await Task.Delay(
|
||
TimeSpan.FromSeconds(Math.Clamp(_connection.PostRestartDelaySeconds, 0, 120)),
|
||
cancellationToken);
|
||
|
||
return (true, $"Container '{containerName}' neugestartet",
|
||
$"Domain={_connection.DomainName}; URL={_connection.ConnectionUrl}\n{output}");
|
||
}
|
||
|
||
return (false, "Neustart fehlgeschlagen",
|
||
$"Container '{containerName}', Domain '{_connection.DomainName}', URL {_connection.ConnectionUrl}\n" +
|
||
$"Fehler: {error}\n\n{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 string Truncate(string? s, int max = 180)
|
||
=> string.IsNullOrWhiteSpace(s) ? string.Empty
|
||
: s.Length <= max ? s : s[..max] + "…";
|
||
|
||
public void Dispose()
|
||
{
|
||
// nichts zu dispose'n
|
||
}
|
||
}
|