Implement MongoDB-based storage for Pack Run approval, artifact, log, and state management
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Added MongoPackRunApprovalStore for managing approval states with MongoDB. - Introduced MongoPackRunArtifactUploader for uploading and storing artifacts. - Created MongoPackRunLogStore to handle logging of pack run events. - Developed MongoPackRunStateStore for persisting and retrieving pack run states. - Implemented unit tests for MongoDB stores to ensure correct functionality. - Added MongoTaskRunnerTestContext for setting up MongoDB test environment. - Enhanced PackRunStateFactory to correctly initialize state with gate reasons.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace StellaOps.TaskRunner.Core.Configuration;
|
||||
|
||||
public static class TaskRunnerStorageModes
|
||||
{
|
||||
public const string Filesystem = "filesystem";
|
||||
public const string Mongo = "mongo";
|
||||
}
|
||||
|
||||
public sealed class TaskRunnerStorageOptions
|
||||
{
|
||||
public string Mode { get; set; } = TaskRunnerStorageModes.Filesystem;
|
||||
|
||||
public TaskRunnerMongoOptions Mongo { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class TaskRunnerMongoOptions
|
||||
{
|
||||
public string ConnectionString { get; set; } = "mongodb://127.0.0.1:27017/stellaops-taskrunner";
|
||||
|
||||
public string? Database { get; set; }
|
||||
|
||||
public string RunsCollection { get; set; } = "pack_runs";
|
||||
|
||||
public string LogsCollection { get; set; } = "pack_run_logs";
|
||||
|
||||
public string ArtifactsCollection { get; set; } = "pack_artifacts";
|
||||
|
||||
public string ApprovalsCollection { get; set; } = "pack_run_approvals";
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
namespace StellaOps.TaskRunner.Core.Execution;
|
||||
|
||||
/// <summary>
|
||||
/// Persists pack run log entries in a deterministic append-only fashion.
|
||||
/// </summary>
|
||||
public interface IPackRunLogStore
|
||||
{
|
||||
/// <summary>
|
||||
/// Appends a single log entry to the run log.
|
||||
/// </summary>
|
||||
Task AppendAsync(string runId, PackRunLogEntry entry, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the log entries for the specified run in chronological order.
|
||||
/// </summary>
|
||||
IAsyncEnumerable<PackRunLogEntry> ReadAsync(string runId, CancellationToken cancellationToken);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether any log entries exist for the specified run.
|
||||
/// </summary>
|
||||
Task<bool> ExistsAsync(string runId, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single structured log entry emitted during a pack run.
|
||||
/// </summary>
|
||||
public sealed record PackRunLogEntry(
|
||||
DateTimeOffset Timestamp,
|
||||
string Level,
|
||||
string EventType,
|
||||
string Message,
|
||||
string? StepId,
|
||||
IReadOnlyDictionary<string, string>? Metadata);
|
||||
@@ -0,0 +1,116 @@
|
||||
using StellaOps.TaskRunner.Core.Execution.Simulation;
|
||||
|
||||
namespace StellaOps.TaskRunner.Core.Execution;
|
||||
|
||||
/// <summary>
|
||||
/// Builds deterministic <see cref="PackRunState"/> snapshots for freshly scheduled runs.
|
||||
/// </summary>
|
||||
public static class PackRunStateFactory
|
||||
{
|
||||
public static PackRunState CreateInitialState(
|
||||
PackRunExecutionContext context,
|
||||
PackRunExecutionGraph graph,
|
||||
PackRunSimulationEngine simulationEngine,
|
||||
DateTimeOffset timestamp)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
ArgumentNullException.ThrowIfNull(graph);
|
||||
ArgumentNullException.ThrowIfNull(simulationEngine);
|
||||
|
||||
var simulation = simulationEngine.Simulate(context.Plan);
|
||||
var simulationIndex = IndexSimulation(simulation.Steps);
|
||||
|
||||
var stepRecords = new Dictionary<string, PackRunStepStateRecord>(StringComparer.Ordinal);
|
||||
foreach (var step in EnumerateSteps(graph.Steps))
|
||||
{
|
||||
var simulationStatus = simulationIndex.TryGetValue(step.Id, out var node)
|
||||
? node.Status
|
||||
: PackRunSimulationStatus.Pending;
|
||||
|
||||
var status = step.Enabled ? PackRunStepExecutionStatus.Pending : PackRunStepExecutionStatus.Skipped;
|
||||
string? statusReason = null;
|
||||
|
||||
if (!step.Enabled)
|
||||
{
|
||||
statusReason = "disabled";
|
||||
}
|
||||
else if (simulationStatus == PackRunSimulationStatus.RequiresApproval)
|
||||
{
|
||||
statusReason = "requires-approval";
|
||||
}
|
||||
else if (simulationStatus == PackRunSimulationStatus.RequiresPolicy)
|
||||
{
|
||||
statusReason = "requires-policy";
|
||||
}
|
||||
else if (simulationStatus == PackRunSimulationStatus.Skipped)
|
||||
{
|
||||
status = PackRunStepExecutionStatus.Skipped;
|
||||
statusReason = "condition-false";
|
||||
}
|
||||
|
||||
var record = new PackRunStepStateRecord(
|
||||
step.Id,
|
||||
step.Kind,
|
||||
step.Enabled,
|
||||
step.ContinueOnError,
|
||||
step.MaxParallel,
|
||||
step.ApprovalId,
|
||||
step.GateMessage,
|
||||
status,
|
||||
Attempts: 0,
|
||||
LastTransitionAt: null,
|
||||
NextAttemptAt: null,
|
||||
StatusReason: statusReason);
|
||||
|
||||
stepRecords[step.Id] = record;
|
||||
}
|
||||
|
||||
var failurePolicy = graph.FailurePolicy ?? PackRunExecutionGraph.DefaultFailurePolicy;
|
||||
|
||||
return PackRunState.Create(
|
||||
context.RunId,
|
||||
context.Plan.Hash,
|
||||
context.Plan,
|
||||
failurePolicy,
|
||||
context.RequestedAt,
|
||||
stepRecords,
|
||||
timestamp);
|
||||
}
|
||||
|
||||
private static Dictionary<string, PackRunSimulationNode> IndexSimulation(IReadOnlyList<PackRunSimulationNode> nodes)
|
||||
{
|
||||
var result = new Dictionary<string, PackRunSimulationNode>(StringComparer.Ordinal);
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
IndexSimulationNode(node, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void IndexSimulationNode(PackRunSimulationNode node, Dictionary<string, PackRunSimulationNode> accumulator)
|
||||
{
|
||||
accumulator[node.Id] = node;
|
||||
foreach (var child in node.Children)
|
||||
{
|
||||
IndexSimulationNode(child, accumulator);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<PackRunExecutionStep> EnumerateSteps(IReadOnlyList<PackRunExecutionStep> steps)
|
||||
{
|
||||
foreach (var step in steps)
|
||||
{
|
||||
yield return step;
|
||||
if (step.Children.Count == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var child in EnumerateSteps(step.Children))
|
||||
{
|
||||
yield return child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user