Skip to content

Commit 4029431

Browse files
paule96davidfowl
authored andcommitted
#2367 dapr change the app port depending on the app protocol (#3184)
* 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 Co-authored-by: David Fowler <davidfowl@gmail.com> * 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: David Fowler <davidfowl@gmail.com>
1 parent 455f6cd commit 4029431

File tree

3 files changed

+125
-11
lines changed

3 files changed

+125
-11
lines changed

src/Aspire.Hosting.Dapr/DaprDistributedApplicationLifecycleHook.cs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
9999
var daprMetricsPortArg = (object port) => ModelNamedObjectArg("--metrics-port", port);
100100
var daprProfilePortArg = (object port) => ModelNamedObjectArg("--profile-port", port);
101101
var daprAppChannelAddressArg = (string? address) => ModelNamedArg("--app-channel-address", address);
102+
var daprAppProtocol = (string? protocol) => ModelNamedArg("--app-protocol", protocol);
102103

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

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

162163
// NOTE: Telemetry is enabled by default.
@@ -170,15 +171,12 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
170171
updatedArgs =>
171172
{
172173
updatedArgs.AddRange(daprCommandLine.Arguments);
173-
174-
EndpointReference? httpEndPoint = null;
175-
if (resource is IResourceWithEndpoints resourceWithEndpoints)
174+
var endPoint = GetEndpointReference(sidecarOptions, resource);
175+
if (endPoint is not null)
176176
{
177-
httpEndPoint = resourceWithEndpoints.GetEndpoint("http");
178-
179-
if (httpEndPoint.IsAllocated && sidecarOptions?.AppPort is null)
177+
if (endPoint.Value.appEndpoint.IsAllocated && sidecarOptions?.AppPort is null)
180178
{
181-
updatedArgs.AddRange(daprAppPortArg(httpEndPoint.Port)());
179+
updatedArgs.AddRange(daprAppPortArg(endPoint.Value.appEndpoint.Port)());
182180
}
183181
}
184182

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

200-
if (sidecarOptions?.AppChannelAddress is null && httpEndPoint is not null)
198+
if (sidecarOptions?.AppChannelAddress is null && endPoint is not null)
201199
{
202-
updatedArgs.AddRange(daprAppChannelAddressArg(httpEndPoint.Host)());
200+
updatedArgs.AddRange(daprAppChannelAddressArg(endPoint.Value.appEndpoint.Host)());
201+
}
202+
if (sidecarOptions?.AppProtocol is null && endPoint is not null)
203+
{
204+
updatedArgs.AddRange(daprAppProtocol(endPoint.Value.protocol)());
203205
}
204206
}));
205207

@@ -255,6 +257,27 @@ public async Task BeforeStartAsync(DistributedApplicationModel appModel, Cancell
255257
appModel.Resources.AddRange(sideCars);
256258
}
257259

260+
// This method resolves the application's endpoint and the protocol that the dapr side car will use.
261+
// It depends on DaprSidecarOptions.AppProtocol and DaprSidecarOptions.AppEndpoint.
262+
// - If both are null default to 'http' for both.
263+
// - If AppProtocol is not null try to get an endpoint with the name of the protocol.
264+
// - if AppEndpoint is not null try to use the scheme as the protocol.
265+
// - if both are not null just use both options.
266+
static (EndpointReference appEndpoint, string protocol)? GetEndpointReference(DaprSidecarOptions? sidecarOptions, IResource resource)
267+
{
268+
if (resource is IResourceWithEndpoints resourceWithEndpoints)
269+
{
270+
return (sidecarOptions?.AppProtocol, sidecarOptions?.AppEndpoint) switch
271+
{
272+
(null, null) => (resourceWithEndpoints.GetEndpoint("http"), "http"),
273+
(null, string appEndpoint) => (resourceWithEndpoints.GetEndpoint(appEndpoint), resourceWithEndpoints.GetEndpoint(appEndpoint).Scheme),
274+
(string appProtocol, null) => (resourceWithEndpoints.GetEndpoint(appProtocol), appProtocol),
275+
(string appProtocol, string appEndpoint) => (resourceWithEndpoints.GetEndpoint(appEndpoint), appProtocol)
276+
};
277+
}
278+
return null;
279+
}
280+
258281
/// <summary>
259282
/// Return the first verified dapr path
260283
/// </summary>

src/Aspire.Hosting.Dapr/DaprSidecarOptions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public sealed record DaprSidecarOptions
5555
/// </summary>
5656
public string? AppProtocol { get; init; }
5757

58+
/// <summary>
59+
/// Gets or sets the endpoint of the application the sidecar is connected to.
60+
/// </summary>
61+
public string? AppEndpoint { get; init; }
62+
5863
/// <summary>
5964
/// Gets or sets the command run by the Dapr CLI as part of starting the sidecar.
6065
/// </summary>

tests/Aspire.Hosting.Tests/Dapr/DaprTests.cs

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,96 @@ public async Task WithDaprSideCarAddsAnnotationAndSidecarResource()
7777
"--metrics-port",
7878
"{{- portForServing \"metrics\" -}}",
7979
"--app-channel-address",
80-
"localhost"
80+
"localhost",
81+
"--app-protocol",
82+
"http"
8183
};
8284

8385
Assert.Equal(expectedArgs, sidecarArgs);
8486
Assert.NotNull(container.Annotations.OfType<DaprSidecarAnnotation>());
8587
}
88+
89+
[Theory]
90+
[InlineData("https", "https", 555, "https", "localhost", 555)]
91+
[InlineData(null, null, null, "http", "localhost", 8000)]
92+
[InlineData("https", null, null, "https", "localhost", 8001)]
93+
[InlineData(null, "https", null, "https", "localhost", 8001)]
94+
[InlineData(null, null, 555, "http", "localhost", 555)]
95+
[InlineData("https", "http", null, "https", "localhost", 8000)]
96+
public async Task WithDaprSideCarAddsAnnotationBasedOnTheSidecarAppOptions(string? schema, string? endPoint, int? port, string expectedSchema, string expectedChannelAddress, int expectedPort)
97+
{
98+
using var builder = TestDistributedApplicationBuilder.Create(new DistributedApplicationOptions
99+
{
100+
DisableDashboard = true
101+
});
102+
103+
builder.AddDapr(o =>
104+
{
105+
// Fake path to avoid throwing
106+
o.DaprPath = "dapr";
107+
});
108+
109+
var containerResource = builder.AddContainer("name", "image")
110+
.WithEndpoint("http", e =>
111+
{
112+
e.Port = 8000;
113+
e.UriScheme = "http";
114+
e.AllocatedEndpoint = new(e, "localhost", 8000);
115+
})
116+
.WithEndpoint("https", e =>
117+
{
118+
e.Port = 8001;
119+
e.UriScheme = "https";
120+
e.AllocatedEndpoint = new(e, "localhost", 8001);
121+
});
122+
if (schema is null && endPoint is null && port is null)
123+
{
124+
containerResource.WithDaprSidecar();
125+
}
126+
else
127+
{
128+
containerResource.WithDaprSidecar(new DaprSidecarOptions()
129+
{
130+
AppProtocol = schema,
131+
AppEndpoint = endPoint,
132+
AppPort = port
133+
});
134+
}
135+
using var app = builder.Build();
136+
await app.ExecuteBeforeStartHooksAsync(default);
137+
138+
var model = app.Services.GetRequiredService<DistributedApplicationModel>();
139+
140+
Assert.Equal(3, model.Resources.Count);
141+
var container = Assert.Single(model.Resources.OfType<ContainerResource>());
142+
var sidecarResource = Assert.Single(model.Resources.OfType<IDaprSidecarResource>());
143+
var sideCarCli = Assert.Single(model.Resources.OfType<ExecutableResource>());
144+
145+
Assert.True(sideCarCli.TryGetEndpoints(out var endpoints));
146+
147+
var ports = new Dictionary<string, int>
148+
{
149+
["http"] = 3500,
150+
["grpc"] = 50001,
151+
["metrics"] = 9090
152+
};
153+
154+
foreach (var e in endpoints)
155+
{
156+
e.AllocatedEndpoint = new(e, "localhost", ports[e.Name], targetPortExpression: $$$"""{{- portForServing "{{{e.Name}}}" -}}""");
157+
}
158+
159+
var config = await EnvironmentVariableEvaluator.GetEnvironmentVariablesAsync(container);
160+
var sidecarArgs = await ArgumentEvaluator.GetArgumentListAsync(sideCarCli);
161+
162+
Assert.Equal("http://localhost:3500", config["DAPR_HTTP_ENDPOINT"]);
163+
Assert.Equal("http://localhost:50001", config["DAPR_GRPC_ENDPOINT"]);
164+
165+
// because the order of the parameters is changing, we are just checking if the important ones here.
166+
var commandline = string.Join(" ", sidecarArgs);
167+
Assert.Contains($"--app-port {expectedPort}", commandline);
168+
Assert.Contains($"--app-channel-address {expectedChannelAddress}", commandline);
169+
Assert.Contains($"--app-protocol {expectedSchema}", commandline);
170+
Assert.NotNull(container.Annotations.OfType<DaprSidecarAnnotation>());
171+
}
86172
}

0 commit comments

Comments
 (0)