Skip to content

Fix executable arguments showing raw manifest expressions in dashboard #10896

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
4 changes: 2 additions & 2 deletions src/Aspire.Hosting/ApplicationModel/ExpressionResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ async ValueTask<ResolvedValue> ResolveInternalAsync(object? value)
ConnectionStringReference cs => await ResolveConnectionStringReferenceAsync(cs).ConfigureAwait(false),
IResourceWithConnectionString cs and not ConnectionStringParameterResource => await ResolveInternalAsync(cs.ConnectionStringExpression).ConfigureAwait(false),
ReferenceExpression ex => await EvalExpressionAsync(ex).ConfigureAwait(false),
EndpointReference endpointReference when sourceIsContainer => new ResolvedValue(await EvalEndpointAsync(endpointReference, EndpointProperty.Url).ConfigureAwait(false), false),
EndpointReferenceExpression ep when sourceIsContainer => new ResolvedValue(await EvalEndpointAsync(ep.Endpoint, ep.Property).ConfigureAwait(false), false),
EndpointReference endpointReference => new ResolvedValue(await EvalEndpointAsync(endpointReference, EndpointProperty.Url).ConfigureAwait(false), false),
EndpointReferenceExpression ep => new ResolvedValue(await EvalEndpointAsync(ep.Endpoint, ep.Property).ConfigureAwait(false), false),
IValueProvider vp => await EvalValueProvider(vp).ConfigureAwait(false),
_ => throw new NotImplementedException()
};
Expand Down
62 changes: 62 additions & 0 deletions tests/Aspire.Hosting.Tests/ExpressionResolverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,61 @@ public async Task ContainerToContainerEndpointShouldResolve()

Assert.Equal("http://myContainer:8080", config["ConnectionStrings__myContainer"]);
}

[Theory]
[InlineData(false, false, "Target=12345;")] // executable -> executable
[InlineData(false, true, "Target=12345;")] // executable -> container
[InlineData(true, false, "Target=ContainerHostName:12345;")] // container -> executable
[InlineData(true, true, "Target=testresource:10000;")] // container -> container
public async Task ExecutableEndpointExpressionsShouldResolve(bool sourceIsContainer, bool targetIsContainer, string expectedResult)
{
var builder = DistributedApplication.CreateBuilder();

var target = builder.AddResource(new TestExecutableEndpointResource("testresource"))
.WithEndpoint("endpoint1", e =>
{
e.UriScheme = "http";
e.AllocatedEndpoint = new(e, "localhost", 12345, containerHostAddress: targetIsContainer ? "ContainerHostName" : null, targetPortExpression: "10000");
});

if (targetIsContainer)
{
target = target.WithImage("someimage");
}

// Test endpoint port expression resolution for executable arguments
var endpointRef = new EndpointReference(target.Resource, "endpoint1");
var portExpression = new EndpointReferenceExpression(endpointRef, EndpointProperty.Port);

var result = await ExpressionResolver.ResolveAsync(sourceIsContainer, portExpression, "ContainerHostName", CancellationToken.None).DefaultTimeout();

var expected = expectedResult.Split('=')[1].TrimEnd(';');
Assert.Equal(expected, result.Value);
}

[Fact]
public async Task ExecutableWithEndpointArgumentsResolvesCorrectly()
{
var builder = DistributedApplication.CreateBuilder();

// Create a container resource with an endpoint
var container = builder.AddContainer("testcontainer", "nginx")
.WithHttpEndpoint(targetPort: 8080, port: 12345);

// Create an executable that references the container's endpoint port
var executable = builder.AddExecutable("testexe", "pwsh.exe", ".")
.WithArgs("-port")
.WithArgs(x => x.Args.Add(container.GetEndpoint("http").Property(EndpointProperty.TargetPort)));

// Test that the expression gets resolved for the executable (not container source)
var endpointRef = container.GetEndpoint("http");
var portExpression = endpointRef.Property(EndpointProperty.TargetPort);

var result = await ExpressionResolver.ResolveAsync(false, portExpression, "host.docker.internal", CancellationToken.None).DefaultTimeout();

// For executable accessing container endpoint, should get the host port (since target port would be for container-to-container)
Assert.Equal("12345", result.Value);
}
}

sealed class MyContainerResource : ContainerResource, IResourceWithConnectionString
Expand Down Expand Up @@ -236,3 +291,10 @@ public TestExpressionResolverResource(string exprName) : base("testresource")

public ReferenceExpression ConnectionStringExpression => Expressions[_exprName];
}

sealed class TestExecutableEndpointResource : ContainerResource, IResourceWithEndpoints
{
public TestExecutableEndpointResource(string name) : base(name)
{
}
}
Loading