Skip to content

Commit

Permalink
#2367 dapr change the app port depending on the app protocol (#3184) (#…
Browse files Browse the repository at this point in the history
…3626)

* dapr change the app port depending on the app protocol

* fix endpoint annotations for dapr.

* fix the rest of the endpoints uri schemas

* Apply suggestions from code review



* fix white spaces

* now we can define both, dapr protocol or endpoint from the configured endpoint

* add tests

* revert changes in the playground

* fix spelling issue

* add a large comment for all of this logic

* fix formatting

* Update src/Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs

* change to switch expression fix test

* revert changes in playground

* format stuff

* fix is null and formating

* improve switch

---------

Co-authored-by: paule96 <paul-jeschke@outlook.com>
Co-authored-by: David Fowler <davidfowl@gmail.com>
  • Loading branch information
3 people authored Apr 12, 2024
1 parent 0a21749 commit f80e6ab
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 11 deletions.
43 changes: 33 additions & 10 deletions src/Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
var daprMetricsPortArg = (object port) => ModelNamedObjectArg("--metrics-port", port);
var daprProfilePortArg = (object port) => ModelNamedObjectArg("--profile-port", port);
var daprAppChannelAddressArg = (string? address) => ModelNamedArg("--app-channel-address", address);
var daprAppProtocol = (string? protocol) => ModelNamedArg("--app-protocol", protocol);

var appId = sidecarOptions?.AppId ?? resource.Name;

Expand Down Expand Up @@ -156,7 +157,7 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
daprCli.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, uriScheme: "http", name: "metrics", port: sidecarOptions?.MetricsPort));
if (sidecarOptions?.EnableProfiling == true)
{
daprCli.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, name: "profile", port: sidecarOptions?.ProfilePort));
daprCli.Annotations.Add(new EndpointAnnotation(ProtocolType.Tcp, name: "profile", port: sidecarOptions?.ProfilePort, uriScheme: "http"));
}

// NOTE: Telemetry is enabled by default.
Expand All @@ -170,15 +171,12 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
updatedArgs =>
{
updatedArgs.AddRange(daprCommandLine.Arguments);

EndpointReference? httpEndPoint = null;
if (resource is IResourceWithEndpoints resourceWithEndpoints)
var endPoint = GetEndpointReference(sidecarOptions, resource);
if (endPoint is not null)
{
httpEndPoint = resourceWithEndpoints.GetEndpoint("http");

if (httpEndPoint.IsAllocated && sidecarOptions?.AppPort is null)
if (endPoint.Value.appEndpoint.IsAllocated && sidecarOptions?.AppPort is null)
{
updatedArgs.AddRange(daprAppPortArg(httpEndPoint.Port)());
updatedArgs.AddRange(daprAppPortArg(endPoint.Value.appEndpoint.Port)());
}
}

Expand All @@ -197,9 +195,13 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
updatedArgs.AddRange(daprProfilePortArg(profiling.Property(EndpointProperty.TargetPort))());
}

if (sidecarOptions?.AppChannelAddress is null && httpEndPoint is not null)
if (sidecarOptions?.AppChannelAddress is null && endPoint is not null)
{
updatedArgs.AddRange(daprAppChannelAddressArg(httpEndPoint.Host)());
updatedArgs.AddRange(daprAppChannelAddressArg(endPoint.Value.appEndpoint.Host)());
}
if (sidecarOptions?.AppProtocol is null && endPoint is not null)
{
updatedArgs.AddRange(daprAppProtocol(endPoint.Value.protocol)());
}
}));

Expand Down Expand Up @@ -255,6 +257,27 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
appModel.Resources.AddRange(sideCars);
}

// This method resolves the application's endpoint and the protocol that the dapr side car will use.
// It depends on DaprSidecarOptions.AppProtocol and DaprSidecarOptions.AppEndpoint.
// - If both are null default to 'http' for both.
// - If AppProtocol is not null try to get an endpoint with the name of the protocol.
// - if AppEndpoint is not null try to use the scheme as the protocol.
// - if both are not null just use both options.
static (EndpointReference appEndpoint, string protocol)? GetEndpointReference(DaprSidecarOptions? sidecarOptions, IResource resource)
{
if (resource is IResourceWithEndpoints resourceWithEndpoints)
{
return (sidecarOptions?.AppProtocol, sidecarOptions?.AppEndpoint) switch
{
(null, null) => (resourceWithEndpoints.GetEndpoint("http"), "http"),
(null, string appEndpoint) => (resourceWithEndpoints.GetEndpoint(appEndpoint), resourceWithEndpoints.GetEndpoint(appEndpoint).Scheme),
(string appProtocol, null) => (resourceWithEndpoints.GetEndpoint(appProtocol), appProtocol),
(string appProtocol, string appEndpoint) => (resourceWithEndpoints.GetEndpoint(appEndpoint), appProtocol)
};
}
return null;
}

/// <summary>
/// Return the first verified dapr path
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/Aspire.Hosting.Dapr/DaprSidecarOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public sealed record DaprSidecarOptions
/// </summary>
public string? AppProtocol { get; init; }

/// <summary>
/// Gets or sets the endpoint of the application the sidecar is connected to.
/// </summary>
public string? AppEndpoint { get; init; }

/// <summary>
/// Gets or sets the command run by the Dapr CLI as part of starting the sidecar.
/// </summary>
Expand Down
88 changes: 87 additions & 1 deletion tests/Aspire.Hosting.Tests/Dapr/DaprTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,96 @@ public async Task WithDaprSideCarAddsAnnotationAndSidecarResource()
"--metrics-port",
"{{- portForServing \"metrics\" -}}",
"--app-channel-address",
"localhost"
"localhost",
"--app-protocol",
"http"
};

Assert.Equal(expectedArgs, sidecarArgs);
Assert.NotNull(container.Annotations.OfType<DaprSidecarAnnotation>());
}

[Theory]
[InlineData("https", "https", 555, "https", "localhost", 555)]
[InlineData(null, null, null, "http", "localhost", 8000)]
[InlineData("https", null, null, "https", "localhost", 8001)]
[InlineData(null, "https", null, "https", "localhost", 8001)]
[InlineData(null, null, 555, "http", "localhost", 555)]
[InlineData("https", "http", null, "https", "localhost", 8000)]
public async Task WithDaprSideCarAddsAnnotationBasedOnTheSidecarAppOptions(string? schema, string? endPoint, int? port, string expectedSchema, string expectedChannelAddress, int expectedPort)
{
using var builder = TestDistributedApplicationBuilder.Create(new DistributedApplicationOptions
{
DisableDashboard = true
});

builder.AddDapr(o =>
{
// Fake path to avoid throwing
o.DaprPath = "dapr";
});

var containerResource = builder.AddContainer("name", "image")
.WithEndpoint("http", e =>
{
e.Port = 8000;
e.UriScheme = "http";
e.AllocatedEndpoint = new(e, "localhost", 8000);
})
.WithEndpoint("https", e =>
{
e.Port = 8001;
e.UriScheme = "https";
e.AllocatedEndpoint = new(e, "localhost", 8001);
});
if (schema is null && endPoint is null && port is null)
{
containerResource.WithDaprSidecar();
}
else
{
containerResource.WithDaprSidecar(new DaprSidecarOptions()
{
AppProtocol = schema,
AppEndpoint = endPoint,
AppPort = port
});
}
using var app = builder.Build();
await app.ExecuteBeforeStartHooksAsync(default);

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

Assert.Equal(3, model.Resources.Count);
var container = Assert.Single(model.Resources.OfType<ContainerResource>());
var sidecarResource = Assert.Single(model.Resources.OfType<IDaprSidecarResource>());
var sideCarCli = Assert.Single(model.Resources.OfType<ExecutableResource>());

Assert.True(sideCarCli.TryGetEndpoints(out var endpoints));

var ports = new Dictionary<string, int>
{
["http"] = 3500,
["grpc"] = 50001,
["metrics"] = 9090
};

foreach (var e in endpoints)
{
e.AllocatedEndpoint = new(e, "localhost", ports[e.Name], targetPortExpression: $$$"""{{- portForServing "{{{e.Name}}}" -}}""");
}

var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(container);
var sidecarArgs = await ArgumentEvaluator.GetArgumentListAsync(sideCarCli);

Assert.Equal("http://localhost:3500", config["DAPR_HTTP_ENDPOINT"]);
Assert.Equal("http://localhost:50001", config["DAPR_GRPC_ENDPOINT"]);

// because the order of the parameters is changing, we are just checking if the important ones here.
var commandline = string.Join(" ", sidecarArgs);
Assert.Contains($"--app-port {expectedPort}", commandline);
Assert.Contains($"--app-channel-address {expectedChannelAddress}", commandline);
Assert.Contains($"--app-protocol {expectedSchema}", commandline);
Assert.NotNull(container.Annotations.OfType<DaprSidecarAnnotation>());
}
}

0 comments on commit f80e6ab

Please sign in to comment.