using ZA.CoreService.ESBCertificateManager.Models; namespace ZA.CoreService.ESBCertificateManager.Services; public sealed class SonicContainerDiscovery { private readonly IReadOnlyList _connections; public SonicContainerDiscovery(IReadOnlyList connections) { _connections = connections; } public bool HasConnections => _connections.Count > 0; public IReadOnlyList Connections => _connections; public async Task DiscoverAsync( string connectionName, IReadOnlyList knownTargets, CancellationToken cancellationToken = default) { SonicConnection? connection = _connections .FirstOrDefault(c => string.Equals(c.Name, connectionName, StringComparison.OrdinalIgnoreCase)); if (connection is null) { return SonicDiscoveryResult.Failed(connectionName, $"Sonic-Verbindung '{connectionName}' fehlt in appsettings."); } using SonicManagementClient client = new(connection); (bool reachable, string? pingError, _) = await client.CheckConnectionAsync(cancellationToken); List remoteContainers = []; List diagnostics = []; if (!reachable) { diagnostics.Add($"Ping: {pingError}"); } else { (bool listOk, IReadOnlyList remoteNames, string? listError) = await client.GetContainersAsync(cancellationToken); if (listOk) { remoteContainers.AddRange(remoteNames.Where(n => !n.StartsWith("WARN:", StringComparison.OrdinalIgnoreCase) && !n.StartsWith("INFO:", StringComparison.OrdinalIgnoreCase))); } else if (!string.IsNullOrWhiteSpace(listError)) { diagnostics.Add(listError); } } List merged = []; foreach (string name in remoteContainers .Concat(connection.KnownContainers) .Concat(knownTargets .Where(t => string.Equals(t.SonicConnectionName, connection.Name, StringComparison.OrdinalIgnoreCase)) .Select(t => t.ContainerName)) .Where(n => !string.IsNullOrWhiteSpace(n))) { if (!merged.Any(m => string.Equals(m, name, StringComparison.OrdinalIgnoreCase))) { merged.Add(name); } } if (merged.Count == 0) { return SonicDiscoveryResult.Failed(connectionName, string.Join(" | ", diagnostics.DefaultIfEmpty("Keine Container gefunden."))); } int id = 1; List targets = merged.Select(name => { DeploymentTarget? known = knownTargets.FirstOrDefault(t => string.Equals(t.ContainerName, name, StringComparison.OrdinalIgnoreCase) && string.Equals(t.SonicConnectionName, connection.Name, StringComparison.OrdinalIgnoreCase)); return new DeploymentTarget { Id = known?.Id ?? id++, Name = known?.Name ?? $"{connection.Name} / {name}", Environment = known?.Environment ?? "TEST", IsActive = true, ContainerName = name, SonicConnectionName = connection.Name, SortOrder = known?.SortOrder ?? id * 10 }; }).ToList(); return new SonicDiscoveryResult { ConnectionName = connectionName, DomainName = connection.DomainName, Success = true, ErrorMessage = diagnostics.Count == 0 ? null : string.Join(" | ", diagnostics), DiscoveredTargets = targets, RawContainerNames = remoteContainers }; } } public sealed class SonicDiscoveryResult { public required string ConnectionName { get; init; } public string DomainName { get; init; } = string.Empty; public bool Success { get; init; } public string? ErrorMessage { get; init; } public IReadOnlyList DiscoveredTargets { get; init; } = []; public IReadOnlyList RawContainerNames { get; init; } = []; public static SonicDiscoveryResult Failed(string connectionName, string error) => new() { ConnectionName = connectionName, Success = false, ErrorMessage = error }; }