Skip to content

Commit

Permalink
Add storage to Aspire
Browse files Browse the repository at this point in the history
  • Loading branch information
ejsmith committed Dec 6, 2024
1 parent 95561a5 commit 83a5df3
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/Exceptionless.AppHost/Exceptionless.AppHost.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<PackageReference Include="Aspire.Hosting.NodeJs" Version="9.0.0" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.0.0" />
<PackageReference Include="AspNetCore.HealthChecks.Elasticsearch" Version="8.0.1" />
<PackageReference Include="Foundatio.AWS" Version="11.0.6" />
</ItemGroup>

<ItemGroup>
Expand Down
138 changes: 138 additions & 0 deletions src/Exceptionless.AppHost/Extensions/MinIoExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
using Foundatio.Storage;

namespace Aspire.Hosting;

public static class MinIoExtensions
{
public static IResourceBuilder<MinIoResource> AddMinIo(
this IDistributedApplicationBuilder builder,
string name,
Action<MinIoBuilder>? configure = null)
{
var options = new MinIoBuilder();
configure?.Invoke(options);

var resource = new MinIoResource(name, options.AccessKey, options.SecretKey, options.Bucket ?? "storage");

string? connectionString = null;

builder.Eventing.Subscribe<ResourceReadyEvent>(resource, async (@event, ct) =>
{
connectionString = await resource.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false);

if (connectionString == null)
throw new DistributedApplicationException($"ResourceReadyEvent was published for the '{resource.Name}' resource but the connection string was null.");

var storage = new S3FileStorage(o => o.ConnectionString(connectionString));
try
{
storage.Client.PutBucketAsync(options.Bucket ?? "storage", ct).GetAwaiter().GetResult();
}
catch
{
// ignored
}
});

return builder.AddResource(resource)
.WithImage(MinIoContainerImageTags.Image)
.WithImageRegistry(MinIoContainerImageTags.Registry)
.WithImageTag(MinIoContainerImageTags.Tag)
.WithArgs("server", "/data", "--console-address", $":{MinIoResource.DefaultConsolePort}")
.WithEndpoint(port: options.ApiPort, targetPort: MinIoResource.DefaultApiPort, name: MinIoResource.ApiEndpointName)
.WithHttpEndpoint(port: options.ConsolePort, targetPort: MinIoResource.DefaultConsolePort, name: MinIoResource.ConsoleEndpointName)
.ConfigureCredentials(options)
.ConfigureVolume(options);
}

private static IResourceBuilder<MinIoResource> ConfigureCredentials(
this IResourceBuilder<MinIoResource> builder,
MinIoBuilder options)
{
return builder
.WithEnvironment("MINIO_ROOT_USER", options.AccessKey ?? "minioadmin")
.WithEnvironment("MINIO_ROOT_PASSWORD", options.SecretKey ?? "minioadmin");
}

private static IResourceBuilder<MinIoResource> ConfigureVolume(
this IResourceBuilder<MinIoResource> builder,
MinIoBuilder options)
{
if (!string.IsNullOrEmpty(options.DataVolumePath))
builder = builder.WithVolume(options.DataVolumePath, "/data");

return builder;
}
}

public class MinIoResource(string name, string? accessKey = null, string? secretKey = null, string? bucket = "storage")
: ContainerResource(name), IResourceWithConnectionString
{
internal const string ApiEndpointName = "api";
internal const string ConsoleEndpointName = "console";
internal const int DefaultApiPort = 9000;
internal const int DefaultConsolePort = 9001;

private EndpointReference? _apiReference;
private EndpointReference? _consoleReference;

private EndpointReference ApiEndpoint =>
_apiReference ??= new EndpointReference(this, ApiEndpointName);

private EndpointReference ConsoleEndpoint =>
_consoleReference ??= new EndpointReference(this, ConsoleEndpointName);

public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create(
$"ServiceUrl=http://{ApiEndpoint.Property(EndpointProperty.Host)}:{ApiEndpoint.Property(EndpointProperty.Port)};" +
$"AccessKey={AccessKey ?? "minioadmin"};" +
$"SecretKey={SecretKey ?? "minioadmin"};" +
$"Bucket={Bucket}");

public string? AccessKey { get; } = accessKey;
public string? SecretKey { get; } = secretKey;
public string? Bucket { get; } = bucket;
}

public class MinIoBuilder
{
public int? ApiPort { get; set; }
public int? ConsolePort { get; set; }
public string? AccessKey { get; set; }
public string? SecretKey { get; set; }
public string? Bucket { get; set; }
public string? DataVolumePath { get; set; }

public MinIoBuilder WithPorts(int? apiPort = null, int? consolePort = null)
{
ApiPort = apiPort;
ConsolePort = consolePort;
return this;
}

public MinIoBuilder WithCredentials(string accessKey, string secretKey)
{
AccessKey = accessKey;
SecretKey = secretKey;
return this;
}

public MinIoBuilder WithBucket(string bucket)
{
Bucket = bucket;
return this;
}

public MinIoBuilder WithDataVolume(string path)
{
DataVolumePath = path;
return this;
}
}

internal static class MinIoContainerImageTags
{
internal const string Registry = "docker.io";
internal const string Image = "minio/minio";
internal const string Tag = "latest";
}
5 changes: 5 additions & 0 deletions src/Exceptionless.AppHost/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
.WithDataVolume("exceptionless.data.v1")
.WithKibana(b => b.WithLifetime(ContainerLifetime.Persistent).WithContainerName("Exceptionless-Kibana"));

var storage = builder.AddMinIo("Storage", s => s.WithCredentials("guest", "password").WithPorts(9000))
.WithLifetime(ContainerLifetime.Persistent)
.WithContainerName("Exceptionless-Storage");

var cache = builder.AddRedis("Redis", port: 6379)
.WithImageTag("7.4")
.WithLifetime(ContainerLifetime.Persistent)
Expand All @@ -32,6 +36,7 @@
var api = builder.AddProject<Projects.Exceptionless_Web>("Api", "Exceptionless")
.WithReference(cache)
.WithReference(elastic)
.WithReference(storage)
.WithEnvironment("ConnectionStrings:Email", "smtp://localhost:1025")
.WithEnvironment("RunJobsInProcess", "false")
.WaitFor(elastic)
Expand Down
2 changes: 1 addition & 1 deletion src/Exceptionless.Job/Exceptionless.Job.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.StackExchangeRedis" Version="1.9.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.ElasticsearchClient" Version="1.0.0-beta.5" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.7" />
</ItemGroup>

Expand Down
4 changes: 2 additions & 2 deletions src/Exceptionless.Job/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ public static IHostBuilder CreateHostBuilder(string[] args)
app.UseSerilogRequestLogging(o =>
{
o.MessageTemplate = "TraceId={TraceId} HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms";
o.GetLevel = (context, duration, ex) =>
o.GetLevel = new Func<HttpContext, double, Exception?, LogEventLevel>((context, duration, ex) =>
{
if (ex is not null || context.Response.StatusCode > 499)
return LogEventLevel.Error;

return duration < 1000 && context.Response.StatusCode < 400 ? LogEventLevel.Debug : LogEventLevel.Information;
};
});
});

Bootstrapper.LogConfiguration(app.ApplicationServices, options, app.ApplicationServices.GetRequiredService<ILogger<Program>>());
Expand Down
4 changes: 2 additions & 2 deletions src/Exceptionless.Web/ApmExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public static IHostBuilder AddApm(this IHostBuilder builder, ApmConfig config)

b.AddAspNetCoreInstrumentation(o =>
{
o.Filter = context =>
o.Filter = new Func<HttpContext, bool>(context =>
{
if (context.Request.Path.StartsWithSegments("/api/v2/push", StringComparison.OrdinalIgnoreCase))
return false;
Expand All @@ -48,7 +48,7 @@ public static IHostBuilder AddApm(this IHostBuilder builder, ApmConfig config)
return false;

return true;
};
});
});

b.AddElasticsearchClientInstrumentation(c =>
Expand Down
2 changes: 1 addition & 1 deletion src/Exceptionless.Web/Exceptionless.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<PackageReference Include="OpenTelemetry.Instrumentation.Http" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.StackExchangeRedis" Version="1.9.0-beta.1" />
<PackageReference Include="OpenTelemetry.Instrumentation.ElasticsearchClient" Version="1.0.0-beta.5" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.10.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="0.5.0-beta.7" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="7.1.0" />
<PackageReference Include="Unchase.Swashbuckle.AspNetCore.Extensions" Version="2.7.1" />
Expand Down
5 changes: 3 additions & 2 deletions src/Exceptionless.Web/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Foundatio.Extensions.Hosting.Startup;
using Foundatio.Repositories.Exceptions;
using Joonasw.AspNetCore.SecurityHeaders;
using Joonasw.AspNetCore.SecurityHeaders.Csp;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.AspNetCore.Hosting.Server.Features;
Expand Down Expand Up @@ -299,11 +300,11 @@ ApplicationException applicationException when applicationException.Message.Cont
.To("https://api-iam.intercom.io/")
.To("wss://nexus-websocket-a.intercom.io");

csp.OnSendingHeader = context =>
csp.OnSendingHeader = new Func<CspSendingHeaderContext, Task>(context =>
{
context.ShouldNotSend = context.HttpContext.Request.Path.StartsWithSegments("/api");
return Task.CompletedTask;
};
});
});

app.UseSerilogRequestLogging(o =>
Expand Down

0 comments on commit 83a5df3

Please sign in to comment.