Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal sealed class ContainerAppEnvironmentContext(

public IAzureContainerAppEnvironment Environment => environment;

private readonly Dictionary<IResource, ContainerAppContext> _containerApps = [];
private readonly Dictionary<IResource, ContainerAppContext> _containerApps = new(new ResourceComparer());

public ContainerAppContext GetContainerAppContext(IResource resource)
{
Expand Down
22 changes: 22 additions & 0 deletions src/Aspire.Hosting.Azure.AppContainers/ResourceComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Aspire.Hosting.ApplicationModel;

namespace Aspire.Hosting.Azure.AppContainers;

internal sealed class ResourceComparer : IEqualityComparer<IResource>
{
public bool Equals(IResource? x, IResource? y)
{
if (x is null || y is null)
{
return false;
}

return x.Name.Equals(y.Name, StringComparison.Ordinal);
}

public int GetHashCode(IResource obj) =>
obj.Name.GetHashCode(StringComparison.Ordinal);
}
28 changes: 27 additions & 1 deletion tests/Aspire.Hosting.Azure.Tests/AzureAppServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,37 @@ await Verify(manifest.ToString(), "json")
.UseHelixAwareDirectory();
}

[Fact]
public async Task AzureAppServiceDoesNotSupportBaitAndSwitchResources()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you rename this test now that its fixed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is app service. When I add support for containers then this will be relevant.

{
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);

builder.AddAzureAppServiceEnvironment("env");

builder.AddProject<Project>("api", launchProfileName: null)
.PublishAsDockerFile()
.WithHttpEndpoint(env: "PORT");

using var app = builder.Build();

var model = app.Services.GetRequiredService<DistributedApplicationModel>();

await ExecuteBeforeStartHooksAsync(app, default);

var container = Assert.Single(model.GetContainerResources());

container.TryGetLastAnnotation<DeploymentTargetAnnotation>(out var target);

var resource = target?.DeploymentTarget as AzureProvisioningResource;

Assert.Null(resource);
}

private static Task<(JsonNode ManifestNode, string BicepText)> GetManifestWithBicep(IResource resource) =>
AzureManifestUtils.GetManifestWithBicep(resource, skipPreparer: true);

private sealed class Project : IProjectMetadata
{
public string ProjectPath => "project";
public string ProjectPath => "/foo/bar/project.csproj";
}
}
34 changes: 33 additions & 1 deletion tests/Aspire.Hosting.Azure.Tests/AzureContainerAppsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public async Task AddExecutableResourceWithPublishAsDockerFileWithAppsInfrastruc

var model = app.Services.GetRequiredService<DistributedApplicationModel>();

var container = Assert.IsType<IComputeResource>(Assert.Single(model.GetContainerResources()), exactMatch: false);
var container = Assert.IsType<IComputeResource>(Assert.Single(model.GetContainerResources()), exactMatch: false);

var target = container.GetDeploymentTargetAnnotation();

Expand Down Expand Up @@ -426,6 +426,38 @@ await Verify(manifest.ToString(), "json")
.UseHelixAwareDirectory();
}

[Fact]
public async Task AzureContainerAppsMapsPortsForBaitAndSwitchResources()
{
var builder = TestDistributedApplicationBuilder.Create(DistributedApplicationOperation.Publish);

builder.AddAzureContainerAppEnvironment("env");

builder.AddExecutable("api", "node", ".")
.PublishAsDockerFile()
.WithHttpEndpoint(env: "PORT");

using var app = builder.Build();

var model = app.Services.GetRequiredService<DistributedApplicationModel>();

await ExecuteBeforeStartHooksAsync(app, default);

var container = Assert.Single(model.GetContainerResources());

container.TryGetLastAnnotation<DeploymentTargetAnnotation>(out var target);

var resource = target?.DeploymentTarget as AzureProvisioningResource;

Assert.NotNull(resource);

var (manifest, bicep) = await GetManifestWithBicep(resource);

await Verify(manifest.ToString(), "json")
.AppendContentAsFile(bicep, "bicep")
.UseHelixAwareDirectory();
}

[Fact]
public void MultipleCallsToAddAzureContainerAppEnvironmentThrows()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param env_outputs_azure_container_apps_environment_default_domain string

param env_outputs_azure_container_apps_environment_id string

param env_outputs_azure_container_registry_endpoint string

param env_outputs_azure_container_registry_managed_identity_id string

param api_containerimage string

resource api 'Microsoft.App/containerApps@2024-03-01' = {
name: 'api'
location: location
properties: {
configuration: {
activeRevisionsMode: 'Single'
ingress: {
external: false
targetPort: 8000
transport: 'http'
}
registries: [
{
server: env_outputs_azure_container_registry_endpoint
identity: env_outputs_azure_container_registry_managed_identity_id
}
]
}
environmentId: env_outputs_azure_container_apps_environment_id
template: {
containers: [
{
image: api_containerimage
name: 'api'
env: [
{
name: 'PORT'
value: '8000'
}
]
}
]
scale: {
minReplicas: 1
}
}
}
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${env_outputs_azure_container_registry_managed_identity_id}': { }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"type": "azure.bicep.v0",
"path": "api.module.bicep",
"params": {
"env_outputs_azure_container_apps_environment_default_domain": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_DEFAULT_DOMAIN}",
"env_outputs_azure_container_apps_environment_id": "{env.outputs.AZURE_CONTAINER_APPS_ENVIRONMENT_ID}",
"env_outputs_azure_container_registry_endpoint": "{env.outputs.AZURE_CONTAINER_REGISTRY_ENDPOINT}",
"env_outputs_azure_container_registry_managed_identity_id": "{env.outputs.AZURE_CONTAINER_REGISTRY_MANAGED_IDENTITY_ID}",
"api_containerimage": "{api.containerImage}"
}
}