Initial commit: ESB Certificate Manager.
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
using Microsoft.Data.SqlClient;
|
||||
using ZA.CoreService.ESBCertificateManager.Models;
|
||||
|
||||
namespace ZA.CoreService.ESBCertificateManager.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Schreibt Deployment-Lauf-Ergebnisse in die SQL-Datenbank.
|
||||
/// Tabellen: dbo.DeploymentRuns (GUID-PK) + dbo.DeploymentTargetResults.
|
||||
/// Ist kein ConnectionString konfiguriert, werden alle Operationen still übersprungen.
|
||||
/// </summary>
|
||||
public sealed class SqlRunLogger
|
||||
{
|
||||
private readonly string? _connectionString;
|
||||
|
||||
public SqlRunLogger(string? connectionString)
|
||||
{
|
||||
_connectionString = string.IsNullOrWhiteSpace(connectionString)
|
||||
? null
|
||||
: connectionString;
|
||||
}
|
||||
|
||||
public bool IsEnabled => _connectionString is not null;
|
||||
|
||||
/// <summary>
|
||||
/// Legt einen neuen Lauf-Datensatz an.
|
||||
/// </summary>
|
||||
public async Task BeginRunAsync(
|
||||
Guid runId,
|
||||
DateTimeOffset startedAt,
|
||||
string certificateFilePath,
|
||||
string certificateFingerprint,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_connectionString is null) return;
|
||||
|
||||
const string sql = """
|
||||
INSERT INTO dbo.DeploymentRuns
|
||||
(Id, StartedAtUtc, SourceFile, SourceFingerprint, StartedBy, MachineName, OverallStatus)
|
||||
VALUES
|
||||
(@Id, @StartedAtUtc, @SourceFile, @SourceFingerprint, @StartedBy, @MachineName, N'Running');
|
||||
""";
|
||||
|
||||
await using SqlConnection conn = new(_connectionString);
|
||||
await conn.OpenAsync(cancellationToken);
|
||||
await using SqlCommand cmd = new(sql, conn);
|
||||
|
||||
cmd.Parameters.AddWithValue("@Id", runId);
|
||||
cmd.Parameters.AddWithValue("@StartedAtUtc", startedAt.UtcDateTime);
|
||||
cmd.Parameters.AddWithValue("@SourceFile", Path.GetFileName(certificateFilePath));
|
||||
cmd.Parameters.AddWithValue("@SourceFingerprint", certificateFingerprint);
|
||||
cmd.Parameters.AddWithValue("@StartedBy", Environment.UserName);
|
||||
cmd.Parameters.AddWithValue("@MachineName", Environment.MachineName);
|
||||
|
||||
await cmd.ExecuteNonQueryAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Aktualisiert den Lauf-Datensatz mit Endzeitpunkt und Gesamtstatus.
|
||||
/// </summary>
|
||||
public async Task CompleteRunAsync(
|
||||
Guid runId,
|
||||
DateTimeOffset finishedAt,
|
||||
bool overallSuccess,
|
||||
int successCount,
|
||||
int totalCount,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_connectionString is null) return;
|
||||
|
||||
string status = overallSuccess
|
||||
? "Success"
|
||||
: (successCount > 0 ? "PartialFailure" : "Failure");
|
||||
|
||||
const string sql = """
|
||||
UPDATE dbo.DeploymentRuns
|
||||
SET FinishedAtUtc = @FinishedAtUtc,
|
||||
OverallStatus = @OverallStatus
|
||||
WHERE Id = @Id;
|
||||
""";
|
||||
|
||||
await using SqlConnection conn = new(_connectionString);
|
||||
await conn.OpenAsync(cancellationToken);
|
||||
await using SqlCommand cmd = new(sql, conn);
|
||||
|
||||
cmd.Parameters.AddWithValue("@Id", runId);
|
||||
cmd.Parameters.AddWithValue("@FinishedAtUtc", finishedAt.UtcDateTime);
|
||||
cmd.Parameters.AddWithValue("@OverallStatus", status);
|
||||
|
||||
await cmd.ExecuteNonQueryAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schreibt das Ergebnis eines einzelnen Deployment-Ziels.
|
||||
/// </summary>
|
||||
public async Task WriteTargetResultAsync(
|
||||
Guid runId,
|
||||
TargetStepResult step,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_connectionString is null) return;
|
||||
|
||||
string status = step.Success ? "Success" : "Failure";
|
||||
|
||||
const string sql = """
|
||||
INSERT INTO dbo.DeploymentTargetResults
|
||||
(DeploymentRunId, TargetId, TargetName,
|
||||
StartedAtUtc, FinishedAtUtc,
|
||||
CopySucceeded, RestartSucceeded, TlsSucceeded,
|
||||
ObservedFingerprint, Status, ErrorMessage)
|
||||
VALUES
|
||||
(@RunId, @TargetId, @TargetName,
|
||||
@StartedAtUtc, @FinishedAtUtc,
|
||||
@CopySucceeded, @RestartSucceeded, @TlsSucceeded,
|
||||
@ObservedFingerprint, @Status, @ErrorMessage);
|
||||
""";
|
||||
|
||||
await using SqlConnection conn = new(_connectionString);
|
||||
await conn.OpenAsync(cancellationToken);
|
||||
await using SqlCommand cmd = new(sql, conn);
|
||||
|
||||
cmd.Parameters.AddWithValue("@RunId", runId);
|
||||
cmd.Parameters.AddWithValue("@TargetId", step.TargetId);
|
||||
cmd.Parameters.AddWithValue("@TargetName", step.TargetName);
|
||||
cmd.Parameters.AddWithValue("@StartedAtUtc", step.StartedAt.UtcDateTime);
|
||||
cmd.Parameters.AddWithValue("@FinishedAtUtc", step.FinishedAt.UtcDateTime);
|
||||
cmd.Parameters.AddWithValue("@CopySucceeded", step.CopySucceeded);
|
||||
cmd.Parameters.AddWithValue("@RestartSucceeded", step.RestartSucceeded);
|
||||
cmd.Parameters.AddWithValue("@TlsSucceeded", step.TlsSucceeded);
|
||||
cmd.Parameters.AddWithValue("@ObservedFingerprint", (object?)step.ObservedFingerprint ?? DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@Status", status);
|
||||
cmd.Parameters.AddWithValue("@ErrorMessage", step.Success ? DBNull.Value : (object?)(step.Detail ?? step.StatusText));
|
||||
|
||||
await cmd.ExecuteNonQueryAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Persistiert ein vollständiges <see cref="DeploymentRunResult"/> in einem einzigen Aufruf.
|
||||
/// </summary>
|
||||
public async Task PersistRunResultAsync(
|
||||
DeploymentRunResult runResult,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_connectionString is null) return;
|
||||
|
||||
await BeginRunAsync(
|
||||
runResult.RunId,
|
||||
runResult.StartedAt,
|
||||
runResult.CertificateFilePath,
|
||||
runResult.CertificateFingerprint,
|
||||
cancellationToken);
|
||||
|
||||
foreach (TargetStepResult step in runResult.TargetResults)
|
||||
{
|
||||
await WriteTargetResultAsync(runResult.RunId, step, cancellationToken);
|
||||
}
|
||||
|
||||
int successCount = runResult.TargetResults.Count(r => r.Success);
|
||||
|
||||
await CompleteRunAsync(
|
||||
runResult.RunId,
|
||||
runResult.FinishedAt,
|
||||
runResult.OverallSuccess,
|
||||
successCount,
|
||||
runResult.TargetResults.Count,
|
||||
cancellationToken);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user