big changes
This commit is contained in:
@@ -8,15 +8,24 @@ namespace ZA.CoreService.ESBCertificateManager.Services;
|
||||
public sealed class DeploymentOrchestrator
|
||||
{
|
||||
private readonly RestartExecutor _restartExecutor;
|
||||
private readonly LocalCertificateDeployer _localCertificateDeployer;
|
||||
private readonly PreflightValidator _preflightValidator = new();
|
||||
private readonly AppSettings _settings;
|
||||
|
||||
public DeploymentOrchestrator(AppSettings settings)
|
||||
public DeploymentOrchestrator(
|
||||
AppSettings settings,
|
||||
IReadOnlyList<SonicConnection> sonicConnections)
|
||||
{
|
||||
_settings = settings;
|
||||
_restartExecutor = new RestartExecutor(settings.SonicConnections);
|
||||
|
||||
_restartExecutor =
|
||||
new RestartExecutor(sonicConnections);
|
||||
|
||||
_localCertificateDeployer =
|
||||
new LocalCertificateDeployer();
|
||||
}
|
||||
|
||||
|
||||
public PreflightValidationResult ValidateRestartOnly(IReadOnlyList<DeploymentTarget> selectedTargets)
|
||||
=> _preflightValidator.ValidateRestartOnly(selectedTargets);
|
||||
|
||||
@@ -52,7 +61,75 @@ public sealed class DeploymentOrchestrator
|
||||
|
||||
return runResult;
|
||||
}
|
||||
public async Task<DeploymentRunResult> DeployAsync(
|
||||
string certificateFilePath,
|
||||
string certificateFingerprint,
|
||||
IReadOnlyList<DeploymentTarget> selectedTargets,
|
||||
IProgress<TargetProgressUpdate>? progress,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(certificateFilePath))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Es wurde kein Zertifikatsdateipfad angegeben.",
|
||||
nameof(certificateFilePath));
|
||||
}
|
||||
|
||||
if (!File.Exists(certificateFilePath))
|
||||
{
|
||||
throw new FileNotFoundException(
|
||||
"Die ausgewählte Zertifikatsdatei wurde nicht gefunden.",
|
||||
certificateFilePath);
|
||||
}
|
||||
|
||||
if (selectedTargets.Count == 0)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Es wurde kein Bereitstellungsziel ausgewählt.",
|
||||
nameof(selectedTargets));
|
||||
}
|
||||
|
||||
DateTimeOffset startedAt = DateTimeOffset.Now;
|
||||
List<TargetStepResult> results = [];
|
||||
|
||||
using RunLogger logger = new(_settings.LogDirectory);
|
||||
|
||||
logger.Write(
|
||||
$"Deployment gestartet für {selectedTargets.Count} Ziel(e). " +
|
||||
$"Zertifikat={Path.GetFileName(certificateFilePath)}");
|
||||
|
||||
foreach (DeploymentTarget target in selectedTargets)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
TargetStepResult result = await DeployTargetAsync(
|
||||
certificateFilePath,
|
||||
target,
|
||||
logger,
|
||||
progress,
|
||||
cancellationToken);
|
||||
|
||||
results.Add(result);
|
||||
}
|
||||
|
||||
DateTimeOffset finishedAt = DateTimeOffset.Now;
|
||||
|
||||
DeploymentRunResult runResult = new()
|
||||
{
|
||||
TargetResults = results,
|
||||
StartedAt = startedAt,
|
||||
FinishedAt = finishedAt,
|
||||
CertificateFilePath = certificateFilePath,
|
||||
CertificateFingerprint = certificateFingerprint
|
||||
};
|
||||
|
||||
logger.Write(
|
||||
$"Deployment beendet. Erfolg={runResult.OverallSuccess}; " +
|
||||
$"Dauer={(finishedAt - startedAt).TotalSeconds:F1}s; " +
|
||||
$"Log={logger.LogFilePath}");
|
||||
|
||||
return runResult;
|
||||
}
|
||||
private async Task<TargetStepResult> RestartTargetOnlyAsync(
|
||||
DeploymentTarget target,
|
||||
RunLogger logger,
|
||||
@@ -88,6 +165,125 @@ public sealed class DeploymentOrchestrator
|
||||
progress?.Report(new TargetProgressUpdate(target.Id, restartStatus, restartOk));
|
||||
return targetResult;
|
||||
}
|
||||
private async Task<TargetStepResult> DeployTargetAsync(
|
||||
string certificateFilePath,
|
||||
DeploymentTarget target,
|
||||
RunLogger logger,
|
||||
IProgress<TargetProgressUpdate>? progress,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
List<string> steps = [];
|
||||
DateTimeOffset targetStart = DateTimeOffset.Now;
|
||||
|
||||
try
|
||||
{
|
||||
progress?.Report(new TargetProgressUpdate(
|
||||
target.Id,
|
||||
$"Zertifikat wird nach '{target.TargetDirectory}' kopiert ...",
|
||||
false));
|
||||
|
||||
string deployedFilePath =
|
||||
await _localCertificateDeployer.DeployAsync(
|
||||
certificateFilePath,
|
||||
target.TargetDirectory,
|
||||
target.CertificateFileName,
|
||||
target.BackupEnabled,
|
||||
target.BackupDirectoryName,
|
||||
cancellationToken);
|
||||
|
||||
string copyStatus = $"Zertifikat kopiert: {Path.GetFileName(deployedFilePath)}";
|
||||
|
||||
steps.Add(copyStatus);
|
||||
logger.Write($"[{target.Name}] {copyStatus} | Ziel={deployedFilePath}");
|
||||
|
||||
progress?.Report(new TargetProgressUpdate(
|
||||
target.Id,
|
||||
copyStatus,
|
||||
true));
|
||||
|
||||
return new TargetStepResult
|
||||
{
|
||||
TargetId = target.Id,
|
||||
TargetName = target.Name,
|
||||
Success = true,
|
||||
StatusText = "Kopieren erfolgreich",
|
||||
Detail = deployedFilePath,
|
||||
Steps = steps,
|
||||
StartedAt = targetStart,
|
||||
FinishedAt = DateTimeOffset.Now,
|
||||
|
||||
CopySucceeded = true,
|
||||
RestartSucceeded = true,
|
||||
TlsSucceeded = true,
|
||||
ObservedFingerprint = null
|
||||
};
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorStatus = $"Kopieren fehlgeschlagen: {ex.Message}";
|
||||
|
||||
steps.Add(errorStatus);
|
||||
logger.Write($"[{target.Name}] {errorStatus}");
|
||||
|
||||
progress?.Report(new TargetProgressUpdate(
|
||||
target.Id,
|
||||
errorStatus,
|
||||
false));
|
||||
|
||||
return new TargetStepResult
|
||||
{
|
||||
TargetId = target.Id,
|
||||
TargetName = target.Name,
|
||||
Success = false,
|
||||
StatusText = "Kopieren fehlgeschlagen",
|
||||
Detail = ex.Message,
|
||||
Steps = steps,
|
||||
StartedAt = targetStart,
|
||||
FinishedAt = DateTimeOffset.Now,
|
||||
|
||||
CopySucceeded = false,
|
||||
RestartSucceeded = false,
|
||||
TlsSucceeded = false,
|
||||
ObservedFingerprint = null
|
||||
};
|
||||
}
|
||||
}
|
||||
private static string? CreateCertificateBackup(string currentCertificatePath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(currentCertificatePath) ||
|
||||
!File.Exists(currentCertificatePath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string certificateDirectory =
|
||||
Path.GetDirectoryName(currentCertificatePath)
|
||||
?? throw new InvalidOperationException(
|
||||
$"Kein Zielordner für Zertifikat gefunden: {currentCertificatePath}");
|
||||
|
||||
string backupDirectory = Path.Combine(certificateDirectory, "Backup");
|
||||
Directory.CreateDirectory(backupDirectory);
|
||||
|
||||
string fileNameWithoutExtension =
|
||||
Path.GetFileNameWithoutExtension(currentCertificatePath);
|
||||
|
||||
string extension = Path.GetExtension(currentCertificatePath);
|
||||
|
||||
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
|
||||
|
||||
string backupFileName =
|
||||
$"{fileNameWithoutExtension}_{timestamp}{extension}";
|
||||
|
||||
string backupPath = Path.Combine(backupDirectory, backupFileName);
|
||||
|
||||
File.Copy(currentCertificatePath, backupPath, overwrite: false);
|
||||
|
||||
return backupPath;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly record struct TargetProgressUpdate(int TargetId, string StatusText, bool? SuccessHint);
|
||||
|
||||
Reference in New Issue
Block a user