feat: CommunityToolkit.Aspire.Hosting.Floci — Floci cloud emulator hosing integration - #1479
feat: CommunityToolkit.Aspire.Hosting.Floci — Floci cloud emulator hosing integration#1479edmondshtogu wants to merge 7 commits into
CommunityToolkit.Aspire.Hosting.Floci — Floci cloud emulator hosing integration#1479Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.sh | bash -s -- 1479Or
iex "& { $(irm https://raw.githubusercontent.com/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.ps1) } 1479" |
|
@aaronpowell in addition to this feature I had to fix the restore issue for the security vulnerabilities caused by The PR is ready for your review, so please take a look and let me know if you have any concern. |
5ea6d20 to
04cebcd
Compare
|
@aaronpowell can you take a look please? |
| dependent.Annotations.Add(new EnvironmentCallbackAnnotation(ctx => | ||
| { | ||
| var hostAndPort = ReferenceExpression.Create($"host.docker.internal:{flociPort}"); | ||
| ctx.EnvironmentVariables["PUBSUB_EMULATOR_HOST"] = hostAndPort; |
There was a problem hiding this comment.
Environment variables comment here along the lines of the AWS one - it'd be best to use the .NET config key hierarchy structure if we can.
There was a problem hiding this comment.
This is due to the SDKs' own contract, read by the SDK with no consumer code. In the AWS SDK for .NET, ClientConfig.ServiceURL's getter itself resolves AWS_ENDPOINT_URL_<SERVICE_ID> then falls back to AWS_ENDPOINT_URL (see here and here); same story for the credential/region chain, the GCP *_EMULATOR_HOST set (Google.Cloud.* reads these via EmulatorDetection), and AZURE_STORAGE_CONNECTION_STRING. A Floci__AWS__EndpointUrl key would force every consumer to read config and hand-wire AmazonS3Config.ServiceURL, which defeats the point of an emulator integration. The .NET-idiomatic path is there in parallel: the standard ConnectionStrings__{name} is still injected, so GetConnectionString("floci-aws") works.
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Aspire Community Toolkit hosting integration (CommunityToolkit.Aspire.Hosting.Floci) for running Floci local cloud emulator containers (AWS/Azure/GCP) in an AppHost, including an optional companion Floci UI container and polyglot (TypeScript) AppHost support.
Integration classification (per hosting-integration-authoring):
- Resource shape: container-backed service resources (AWS/Azure/GCP emulators) + companion/admin tool container (Floci UI)
- Lifecycle mode: run-mode oriented (container resources + health checks + runtime env-var injection via events)
- Integration role: local emulator + reference/env-var plumbing for dependent workloads
- Structure: hosting extension methods + resource types + examples + tests + TypeScript AppHost assets
Changes:
- Adds Floci container resources (AWS/Azure/GCP) with shared connection/endpoint plumbing and health checks.
- Adds Floci UI companion resource with “plugged cloud” support to attach multiple emulators to one UI.
- Adds examples (C# + TypeScript) and a new test project covering resource creation and Docker-gated integration scenarios.
Show a summary per file
| File | Description |
|---|---|
| tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/TypeScriptAppHostTests.cs | TypeScript AppHost compile/start coverage |
| tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/MultiCloudUITests.cs | Validates single shared UI + env wiring |
| tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/GcpContainerResourceCreationTests.cs | GCP resource creation/env tests |
| tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/CommunityToolkit.Aspire.Hosting.Floci.Tests.csproj | New Floci test project |
| tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/AzureContainerResourceCreationTests.cs | Azure resource creation/env tests |
| tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/AwsContainerResourceCreationTests.cs | AWS resource creation/env tests |
| tests/CommunityToolkit.Aspire.Hosting.Floci.Tests/AppHostTests.cs | Docker-gated health checks for example AppHost resources |
| src/CommunityToolkit.Aspire.Hosting.Floci/README.md | Integration documentation (C#/TS examples) |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociUIContainerResource.cs | UI companion resource model |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociHostingExtension.Gcp.cs | AddFlociGcp + GCP-specific builder APIs |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociHostingExtension.FlociUI.cs | WithFlociUI + WithPluggedCloud + UI configuration APIs |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociHostingExtension.Common.cs | Shared WithDockerSocket/WithData* implementations |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociHostingExtension.Azure.cs | AddFlociAzure + Azure-specific reference/env wiring |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociHostingExtension.Aws.cs | AddFlociAws + AWS-specific reference/env wiring |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociGcpContainerResource.cs | GCP resource model + UI env wiring |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociContainerResource.cs | Shared base resource + connection properties |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociContainerImageTags.cs | Centralized container image/tag constants |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociAzureContainerResource.cs | Azure resource model + UI env wiring |
| src/CommunityToolkit.Aspire.Hosting.Floci/FlociAwsContainerResource.cs | AWS resource model + UI env wiring |
| src/CommunityToolkit.Aspire.Hosting.Floci/CommunityToolkit.Aspire.Hosting.Floci.csproj | New integration package project |
| README.md | Adds Floci to the integrations table |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost/Program.cs | C# AppHost example wiring AWS/Azure/GCP + shared UI |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost/CommunityToolkit.Aspire.Hosting.Floci.AppHost.csproj | Example AppHost project |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.TypeScript/tsconfig.json | TypeScript AppHost TS config |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.TypeScript/package.json | TypeScript AppHost npm metadata |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.TypeScript/package-lock.json | TypeScript AppHost lockfile |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.TypeScript/eslint.config.mjs | TypeScript AppHost lint config |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.TypeScript/aspire.config.json | TypeScript AppHost Aspire config |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.TypeScript/apphost.mts | TypeScript AppHost example wiring + compile-only API coverage |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.ApiService/Properties/launchSettings.json | Example ApiService launch profile |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.ApiService/Program.cs | Example API exercising AWS/Azure/GCP SDKs |
| examples/floci/CommunityToolkit.Aspire.Hosting.Floci.ApiService/CommunityToolkit.Aspire.Hosting.Floci.ApiService.csproj | Example API project references |
| Directory.Packages.props | Adds Azure.Storage.Blobs + Google.Cloud.Storage.V1 versions |
| CommunityToolkit.Aspire.slnx | Wires new projects into the solution |
Review details
Files not reviewed (1)
- examples/floci/CommunityToolkit.Aspire.Hosting.Floci.AppHost.TypeScript/package-lock.json: Generated file
Suppressed comments (1)
src/CommunityToolkit.Aspire.Hosting.Floci/FlociHostingExtension.Azure.cs:70
- Same as above for host-process dependents: the connection string currently only sets BlobEndpoint. Adding QueueEndpoint/TableEndpoint makes AZURE_STORAGE_CONNECTION_STRING usable by Queue/Table clients as well.
var blobEndpoint = ReferenceExpression.Create($"{resource.ConnectionStringExpression}/{FlociAzureContainerResource.DefaultAccountName}");
ctx.EnvironmentVariables["AZURE_STORAGE_CONNECTION_STRING"] = ReferenceExpression.Create(
$"DefaultEndpointsProtocol=http;AccountName={FlociAzureContainerResource.DefaultAccountName};AccountKey={FlociAzureContainerResource.DefaultAccountKey};BlobEndpoint={blobEndpoint};");
}));
- Files reviewed: 33/34 changed files
- Comments generated: 5
- Review effort level: Lite
Closes floci-io/floci#1242
Adds
CommunityToolkit.Aspire.Hosting.Floci— a hosting integration for Floci, a family of high-performance local cloud emulators (floci/flocifor AWS,floci/floci-azfor Azure,floci/floci-gcpfor GCP) that run as containers inside the Aspire AppHost.What's included
Core integration (
src/CommunityToolkit.Aspire.Hosting.Floci/)AddFlociAws(name, port?, defaultRegion?, defaultAccountId?)— adds the Floci AWS container with an HTTP health check at/_floci/infoAddFlociAzure(name, port?)— adds the Floci Azure container (floci/floci-az), health check at/_floci/healthAddFlociGcp(name, port?, defaultProjectId?)— adds the Floci GCP container (floci/floci-gcp), health check at/_floci-gcp/healthFlociContainerResource) that holds endpoint/connection-string plumbing, soHost,Port,PrimaryEndpoint, andConnectionStringExpressionare implemented once and inherited — not duplicated per cloudWithReferenceautomatically injects the standardConnectionStrings__<name>plus provider-specific env vars via aBeforeStartEventsubscriber; host processes receivelocalhost:{port}, containers receivehost.docker.internal:{port}:AWS_ENDPOINT_URL,AWS_DEFAULT_REGION,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEYAZURE_STORAGE_CONNECTION_STRING(well-knowndevstoreaccount1dev credentials)PUBSUB_EMULATOR_HOST,FIRESTORE_EMULATOR_HOST,DATASTORE_EMULATOR_HOST,STORAGE_EMULATOR_HOST,SECRET_MANAGER_EMULATOR_HOST,GOOGLE_CLOUD_PROJECT,CLOUDSDK_CORE_PROJECTWithDataVolume/WithDataBindMount— switches Floci from in-memory to persistent storage mode; implemented once and shared across all three cloudsWithDockerSocket— mounts the Docker socket so Lambda / Azure Functions / Cloud Run and other container-backed services can launch sibling containers; adds--add-host=host.docker.internal:host-gatewayto container dependents; shared across all three cloudsWithConfigFile(hostPath)— bind-mounts a Quarkusapplication.ymloverride at/deployments/config/application.ymlfor advanced configuration (AWS only — Azure/GCP images don't expose this)Floci UI web console (
WithFlociUI/WithPluggedCloud)WithFlociUI(configureContainer?, containerName?)— available on all three cloud resource types, adds a single sharedFlociUIContainerResourcerunningdocker.io/floci/floci-ui:0.2.0:FLOCI_ENDPOINTfor AWS,FLOCI_AZURE_ENDPOINTfor Azure,FLOCI_GCP_ENDPOINTfor GCP)/; excluded from manifest (ExcludeFromManifest())WithFlociUItwice re-configures the existing UI container instead of adding a duplicateWithReference(cloud)— attaches an additional cloud resource to an already-created UI console, so one console can browse AWS + Azure + GCP at once instead of spinning up three separate UI containers. In C# this is a single overloaded method name; the generated TypeScript bindings expose it aswithAwsReference/withAzureReference/withGcpReferencesince the polyglot export generator needs distinct names when all three overloads share the same target typeWithHostPort(int?)on the UI resource builder to pin the host portExamples and tests
aws.WithFlociUI(configureContainer: ui => { ui.WithPluggedCloud(azure); ui.WithPluggedCloud(gcp); }))ApiServiceexercises all three clouds end-to-end: S3 (AWS SDK), Blob Storage (Azure SDK), and Cloud Storage (GCP SDK), each with its own health check (floci-s3,floci-azure-blob,floci-gcp-storage) and a hosted service that creates a demo bucket/container on startupWithPluggedCloudattaches correctly, single UI container, correct env vars per attached cloud), the TypeScript AppHost, and Docker-gated AppHost integration tests asserting all three cloud resources and the UI resource become healthyConnectionStrings__<name>behavior alongside each cloud's provider-specific env varsPR Checklist
Other information
floci/floci,floci/floci-az,floci/floci-gcp) expose certificate-based configuration the way the earlier AWS-only prototype assumed, so that support was removed rather than shipped half-workingAWS_ENDPOINT_URLis the standard SDK v4 env var; noAmazonS3Config.RegionEndpointshould be set alongsideServiceURL(triggers aNullReferenceExceptionin the v4 endpoint rule engine — documented in the example)StorageClientis built withEmulatorDetection.EmulatorOnlyso it readsSTORAGE_EMULATOR_HOSTand skips real GCP credential resolution entirelyASPIREATS001experimental diagnostic (polyglot export attributes) is suppressed at file level in the hosting extension files