168 lines
6.2 KiB
C#
168 lines
6.2 KiB
C#
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);
|
|
}
|
|
}
|