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:
@@ -1,3 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.RateLimiting;
|
||||
@@ -9,10 +10,13 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.AdvisoryAI.Caching;
|
||||
using StellaOps.AdvisoryAI.Diagnostics;
|
||||
using StellaOps.AdvisoryAI.Hosting;
|
||||
using StellaOps.AdvisoryAI.Metrics;
|
||||
using StellaOps.AdvisoryAI.Outputs;
|
||||
using StellaOps.AdvisoryAI.Orchestration;
|
||||
using StellaOps.AdvisoryAI.Queue;
|
||||
using StellaOps.AdvisoryAI.WebService.Contracts;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@@ -72,6 +76,9 @@ app.MapPost("/v1/advisory-ai/pipeline/{taskType}", HandleSinglePlan)
|
||||
app.MapPost("/v1/advisory-ai/pipeline:batch", HandleBatchPlans)
|
||||
.RequireRateLimiting("advisory-ai");
|
||||
|
||||
app.MapGet("/v1/advisory-ai/outputs/{cacheKey}", HandleGetOutput)
|
||||
.RequireRateLimiting("advisory-ai");
|
||||
|
||||
app.Run();
|
||||
|
||||
static async Task<IResult> HandleSinglePlan(
|
||||
@@ -85,6 +92,10 @@ static async Task<IResult> HandleSinglePlan(
|
||||
AdvisoryPipelineMetrics pipelineMetrics,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using var activity = AdvisoryAiActivitySource.Instance.StartActivity("advisory_ai.plan_request", ActivityKind.Server);
|
||||
activity?.SetTag("advisory.task_type", taskType);
|
||||
activity?.SetTag("advisory.advisory_key", request.AdvisoryKey);
|
||||
|
||||
if (!Enum.TryParse<AdvisoryTaskType>(taskType, ignoreCase: true, out var parsedType))
|
||||
{
|
||||
return Results.BadRequest(new { error = $"Unknown task type '{taskType}'." });
|
||||
@@ -103,6 +114,7 @@ static async Task<IResult> HandleSinglePlan(
|
||||
var normalizedRequest = request with { TaskType = parsedType };
|
||||
var taskRequest = normalizedRequest.ToTaskRequest();
|
||||
var plan = await orchestrator.CreatePlanAsync(taskRequest, cancellationToken).ConfigureAwait(false);
|
||||
activity?.SetTag("advisory.plan_cache_key", plan.CacheKey);
|
||||
|
||||
await planCache.SetAsync(plan.CacheKey, plan, cancellationToken).ConfigureAwait(false);
|
||||
await taskQueue.EnqueueAsync(new AdvisoryTaskQueueMessage(plan.CacheKey, plan.Request), cancellationToken).ConfigureAwait(false);
|
||||
@@ -125,6 +137,9 @@ static async Task<IResult> HandleBatchPlans(
|
||||
AdvisoryPipelineMetrics pipelineMetrics,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
using var activity = AdvisoryAiActivitySource.Instance.StartActivity("advisory_ai.plan_batch", ActivityKind.Server);
|
||||
activity?.SetTag("advisory.batch_size", batchRequest.Requests.Count);
|
||||
|
||||
if (batchRequest.Requests.Count == 0)
|
||||
{
|
||||
return Results.BadRequest(new { error = "At least one request must be supplied." });
|
||||
@@ -153,6 +168,12 @@ static async Task<IResult> HandleBatchPlans(
|
||||
var normalizedRequest = item with { TaskType = parsedType };
|
||||
var taskRequest = normalizedRequest.ToTaskRequest();
|
||||
var plan = await orchestrator.CreatePlanAsync(taskRequest, cancellationToken).ConfigureAwait(false);
|
||||
activity?.AddEvent(new ActivityEvent("advisory.plan.created", tags: new ActivityTagsCollection
|
||||
{
|
||||
{ "advisory.task_type", plan.Request.TaskType.ToString() },
|
||||
{ "advisory.advisory_key", plan.Request.AdvisoryKey },
|
||||
{ "advisory.plan_cache_key", plan.CacheKey }
|
||||
}));
|
||||
|
||||
await planCache.SetAsync(plan.CacheKey, plan, cancellationToken).ConfigureAwait(false);
|
||||
await taskQueue.EnqueueAsync(new AdvisoryTaskQueueMessage(plan.CacheKey, plan.Request), cancellationToken).ConfigureAwait(false);
|
||||
@@ -167,6 +188,37 @@ static async Task<IResult> HandleBatchPlans(
|
||||
return Results.Ok(results);
|
||||
}
|
||||
|
||||
static async Task<IResult> HandleGetOutput(
|
||||
HttpContext httpContext,
|
||||
string cacheKey,
|
||||
string taskType,
|
||||
string? profile,
|
||||
IAdvisoryOutputStore outputStore,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(outputStore);
|
||||
if (!Enum.TryParse<AdvisoryTaskType>(taskType, ignoreCase: true, out var parsedTaskType))
|
||||
{
|
||||
return Results.BadRequest(new { error = $"Unknown task type '{taskType}'." });
|
||||
}
|
||||
|
||||
if (!EnsureAuthorized(httpContext, parsedTaskType))
|
||||
{
|
||||
return Results.StatusCode(StatusCodes.Status403Forbidden);
|
||||
}
|
||||
|
||||
var resolvedProfile = string.IsNullOrWhiteSpace(profile) ? "default" : profile!.Trim();
|
||||
var output = await outputStore.TryGetAsync(cacheKey, parsedTaskType, resolvedProfile, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (output is null)
|
||||
{
|
||||
return Results.NotFound(new { error = "Output not found." });
|
||||
}
|
||||
|
||||
return Results.Ok(AdvisoryOutputResponse.FromDomain(output));
|
||||
}
|
||||
|
||||
static bool EnsureAuthorized(HttpContext context, AdvisoryTaskType taskType)
|
||||
{
|
||||
if (!context.Request.Headers.TryGetValue("X-StellaOps-Scopes", out var scopes))
|
||||
|
||||
Reference in New Issue
Block a user