Skip to content

Commit 972d11d

Browse files
authored
Fix Eureka Dynamic Port Assignment overriding user-configured ports (#1666)
- Detect explicitly configured eureka:instance:port or eureka:instance:securePort to avoid overwriting - Add public UseAspNetCoreUrls property (default: true, to match Consul) to allow disabling dynamic port detection. - Consul optimization: evaluate if port should be set by Steeltoe before collecting listen addresses Made-with: Cursor
1 parent 067370c commit 972d11d

11 files changed

Lines changed: 238 additions & 80 deletions

src/Discovery/src/Consul/Configuration/ConsulDiscoveryOptions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ public sealed class ConsulDiscoveryOptions
175175

176176
/// <summary>
177177
/// Gets or sets a value indicating whether to register with the port number ASP.NET Core is listening on. Default value: true.
178+
/// <para />
179+
/// This property is ignored when <see cref="Port" /> or <see cref="Scheme" /> is explicitly configured, or when <see cref="UseNetworkInterfaces" /> is
180+
/// <c>true</c>.
178181
/// </summary>
179182
public bool UseAspNetCoreUrls { get; set; } = true;
180183
}

src/Discovery/src/Consul/ConfigurationSchema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@
188188
},
189189
"UseAspNetCoreUrls": {
190190
"type": "boolean",
191-
"description": "Gets or sets a value indicating whether to register with the port number ASP.NET Core is listening on. Default value: true."
191+
"description": "Gets or sets a value indicating whether to register with the port number ASP.NET Core is listening on. Default value: true.\n\nThis property is ignored when 'Steeltoe.Discovery.Consul.Configuration.ConsulDiscoveryOptions.Port' or 'Steeltoe.Discovery.Consul.Configuration.ConsulDiscoveryOptions.Scheme' is explicitly configured, or when 'Steeltoe.Discovery.Consul.Configuration.ConsulDiscoveryOptions.UseNetworkInterfaces' is true."
192192
},
193193
"UseNetworkInterfaces": {
194194
"type": "boolean",

src/Discovery/src/Consul/PostConfigureConsulDiscoveryOptions.cs

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public void PostConfigure(string? name, ConsulDiscoveryOptions options)
6262
options.HostName = options.IPAddress;
6363
}
6464

65-
if (options.Port == 0)
65+
if (options is { UseAspNetCoreUrls: true, Port: 0, Scheme: null, UseNetworkInterfaces: false })
6666
{
6767
ICollection<string> addresses = _configuration.GetListenAddresses();
6868
SetSchemeWithPortFromListenAddresses(options, addresses);
@@ -79,38 +79,33 @@ private string GetServiceName(ConsulDiscoveryOptions options)
7979

8080
private void SetSchemeWithPortFromListenAddresses(ConsulDiscoveryOptions options, IEnumerable<string> listenOnAddresses)
8181
{
82-
// Try to pull some values out of server configuration to override defaults, but only if not using NetUtils.
83-
// If NetUtils are configured, the user probably wants to define their own behavior.
84-
if (options is { UseAspNetCoreUrls: true, Port: 0, Scheme: null })
85-
{
86-
int? listenHttpPort = null;
87-
int? listenHttpsPort = null;
82+
int? listenHttpPort = null;
83+
int? listenHttpsPort = null;
8884

89-
foreach (string address in listenOnAddresses)
90-
{
91-
BindingAddress bindingAddress = BindingAddress.Parse(address);
92-
93-
if (bindingAddress is { Scheme: "http", Port: > 0 } && listenHttpPort == null)
94-
{
95-
listenHttpPort = bindingAddress.Port;
96-
}
97-
else if (bindingAddress is { Scheme: "https", Port: > 0 } && listenHttpsPort == null)
98-
{
99-
listenHttpsPort = bindingAddress.Port;
100-
}
101-
}
85+
foreach (string address in listenOnAddresses)
86+
{
87+
BindingAddress bindingAddress = BindingAddress.Parse(address);
10288

103-
if (listenHttpsPort != null)
89+
if (bindingAddress is { Scheme: "http", Port: > 0 } && listenHttpPort == null)
10490
{
105-
options.Port = listenHttpsPort.Value;
106-
options.Scheme = "https";
91+
listenHttpPort = bindingAddress.Port;
10792
}
108-
else if (listenHttpPort != null)
93+
else if (bindingAddress is { Scheme: "https", Port: > 0 } && listenHttpsPort == null)
10994
{
110-
options.Port = listenHttpPort.Value;
111-
options.Scheme = "http";
95+
listenHttpsPort = bindingAddress.Port;
11296
}
11397
}
98+
99+
if (listenHttpsPort != null)
100+
{
101+
options.Port = listenHttpsPort.Value;
102+
options.Scheme = "https";
103+
}
104+
else if (listenHttpPort != null)
105+
{
106+
options.Port = listenHttpPort.Value;
107+
options.Scheme = "http";
108+
}
114109
}
115110

116111
private string GetInstanceId(ConsulDiscoveryOptions options)

src/Discovery/src/Eureka/Configuration/EurekaInstanceOptions.cs

Lines changed: 57 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ public sealed partial class EurekaInstanceOptions
2020
internal const string DefaultStatusPageUrlPath = "/info";
2121
internal const string DefaultHealthCheckUrlPath = "/health";
2222

23-
private bool UseAspNetCoreUrls => !Platform.IsCloudFoundry || IsContainerToContainerMethod() || IsForceHostNameMethod();
23+
private bool IsAnyPortConfigured =>
24+
this is { IsNonSecurePortEnabled: true, NonSecurePort: not null } or { IsSecurePortEnabled: true, SecurePort: not null };
25+
26+
private bool IsSuitableRegistrationMethod => !Platform.IsCloudFoundry || IsContainerToContainerMethod() || IsForceHostNameMethod();
27+
internal bool ShouldSetPortsFromListenAddresses => UseAspNetCoreUrls && IsSuitableRegistrationMethod && !IsAnyPortConfigured;
2428

2529
internal TimeSpan LeaseRenewalInterval => TimeSpan.FromSeconds(LeaseRenewalIntervalInSeconds);
2630
internal TimeSpan LeaseExpirationDuration => TimeSpan.FromSeconds(LeaseExpirationDurationInSeconds);
@@ -205,6 +209,13 @@ public sealed partial class EurekaInstanceOptions
205209
Name = DataCenterName.MyOwn
206210
};
207211

212+
/// <summary>
213+
/// Gets or sets a value indicating whether to register with the port number(s) ASP.NET Core is listening on. Default value: true.
214+
/// <para />
215+
/// This property is ignored when <see cref="NonSecurePort" /> or <see cref="SecurePort" /> is explicitly configured.
216+
/// </summary>
217+
public bool UseAspNetCoreUrls { get; set; } = true;
218+
208219
/// <summary>
209220
/// Gets or sets a value indicating whether <see cref="NetworkInterface.GetAllNetworkInterfaces" /> is used to determine <see cref="IPAddress" /> and
210221
/// <see cref="HostName" />. Default value: false.
@@ -231,72 +242,69 @@ internal bool IsForceHostNameMethod()
231242

232243
internal void SetPortsFromListenAddresses(IEnumerable<string> listenOnAddresses, string source, ILogger<EurekaInstanceOptions> logger)
233244
{
234-
if (UseAspNetCoreUrls)
245+
int? listenHttpPort = null;
246+
int? listenHttpsPort = null;
247+
248+
foreach (string address in listenOnAddresses)
235249
{
236-
int? listenHttpPort = null;
237-
int? listenHttpsPort = null;
250+
BindingAddress bindingAddress = BindingAddress.Parse(address);
238251

239-
foreach (string address in listenOnAddresses)
252+
if (bindingAddress is { Scheme: "http", Port: > 0 } && listenHttpPort == null)
240253
{
241-
BindingAddress bindingAddress = BindingAddress.Parse(address);
242-
243-
if (bindingAddress is { Scheme: "http", Port: > 0 } && listenHttpPort == null)
244-
{
245-
listenHttpPort = bindingAddress.Port;
246-
}
247-
else if (bindingAddress is { Scheme: "https", Port: > 0 } && listenHttpsPort == null)
248-
{
249-
listenHttpsPort = bindingAddress.Port;
250-
}
254+
listenHttpPort = bindingAddress.Port;
255+
}
256+
else if (bindingAddress is { Scheme: "https", Port: > 0 } && listenHttpsPort == null)
257+
{
258+
listenHttpsPort = bindingAddress.Port;
251259
}
260+
}
252261

253-
int? nonSecurePort = IsNonSecurePortEnabled ? NonSecurePort : null;
254-
int? securePort = IsSecurePortEnabled ? SecurePort : null;
262+
int? nonSecurePort = IsNonSecurePortEnabled ? NonSecurePort : null;
263+
int? securePort = IsSecurePortEnabled ? SecurePort : null;
255264

256-
if (nonSecurePort != listenHttpPort)
265+
if (nonSecurePort != listenHttpPort)
266+
{
267+
if (listenHttpPort != null)
257268
{
258-
if (listenHttpPort != null)
269+
if (nonSecurePort == null)
259270
{
260-
if (nonSecurePort == null)
261-
{
262-
LogActivatingNonSecurePort(logger, listenHttpPort, source);
263-
}
264-
else
265-
{
266-
LogChangingNonSecurePort(logger, listenHttpPort, source);
267-
}
268-
269-
NonSecurePort = listenHttpPort.Value;
270-
IsNonSecurePortEnabled = true;
271+
LogActivatingNonSecurePort(logger, listenHttpPort, source);
271272
}
272-
else if (nonSecurePort != null)
273+
else
273274
{
274-
LogDeactivatingNonSecurePort(logger, source);
275-
IsNonSecurePortEnabled = false;
275+
LogChangingNonSecurePort(logger, listenHttpPort, source);
276276
}
277+
278+
NonSecurePort = listenHttpPort.Value;
279+
IsNonSecurePortEnabled = true;
280+
}
281+
else if (nonSecurePort != null)
282+
{
283+
LogDeactivatingNonSecurePort(logger, source);
284+
IsNonSecurePortEnabled = false;
277285
}
286+
}
278287

279-
if (securePort != listenHttpsPort)
288+
if (securePort != listenHttpsPort)
289+
{
290+
if (listenHttpsPort != null)
280291
{
281-
if (listenHttpsPort != null)
292+
if (securePort == null)
282293
{
283-
if (securePort == null)
284-
{
285-
LogActivatingSecurePort(logger, listenHttpsPort, source);
286-
}
287-
else
288-
{
289-
LogChangingSecurePort(logger, listenHttpsPort, source);
290-
}
291-
292-
SecurePort = listenHttpsPort.Value;
293-
IsSecurePortEnabled = true;
294+
LogActivatingSecurePort(logger, listenHttpsPort, source);
294295
}
295-
else if (securePort != null)
296+
else
296297
{
297-
LogDeactivatingSecurePort(logger, source);
298-
IsSecurePortEnabled = false;
298+
LogChangingSecurePort(logger, listenHttpsPort, source);
299299
}
300+
301+
SecurePort = listenHttpsPort.Value;
302+
IsSecurePortEnabled = true;
303+
}
304+
else if (securePort != null)
305+
{
306+
LogDeactivatingSecurePort(logger, source);
307+
IsSecurePortEnabled = false;
300308
}
301309
}
302310
}

src/Discovery/src/Eureka/ConfigurationSchema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,10 @@
258258
"type": "string",
259259
"description": "Gets or sets the relative path to the status page for the instance. The status page URL is then constructed out of the 'Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.HostName' and the type of communication - secure or non-secure, as specified in 'Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.SecurePort' and 'Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.NonSecurePort'. It is normally used for informational purposes for other services to find out about the status of the instance. Users can provide a simple HTML page indicating what the current status of the instance is. Default value: /info."
260260
},
261+
"UseAspNetCoreUrls": {
262+
"type": "boolean",
263+
"description": "Gets or sets a value indicating whether to register with the port number(s) ASP.NET Core is listening on. Default value: true.\n\nThis property is ignored when 'Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.NonSecurePort' or 'Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.SecurePort' is explicitly configured."
264+
},
261265
"UseNetworkInterfaces": {
262266
"type": "boolean",
263267
"description": "Gets or sets a value indicating whether 'System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces' is used to determine 'Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.IPAddress' and 'Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.HostName'. Default value: false."

src/Discovery/src/Eureka/DynamicPortAssignmentHostedService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ public void PostConfigure(string? name, EurekaInstanceOptions options)
136136
{
137137
ArgumentNullException.ThrowIfNull(options);
138138

139-
if (_listenState.ListenOnAddresses != null)
139+
if (_listenState.ListenOnAddresses != null && options.ShouldSetPortsFromListenAddresses)
140140
{
141141
options.SetPortsFromListenAddresses(_listenState.ListenOnAddresses, "address features", _optionsLogger);
142142
}

src/Discovery/src/Eureka/EurekaServiceCollectionExtensions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ private static void ConfigureEurekaClientOptions(IServiceCollection services)
8181

8282
private static void ConfigureEurekaInstanceOptions(IServiceCollection services)
8383
{
84+
DynamicPortAssignmentHostedService.Wire(services);
85+
8486
services.AddOptions<EurekaInstanceOptions>().BindConfiguration(EurekaInstanceOptions.ConfigurationPrefix);
8587
services.AddOptions<InetOptions>().BindConfiguration(InetOptions.ConfigurationPrefix);
8688
services.AddSingleton<IPostConfigureOptions<EurekaInstanceOptions>, PostConfigureEurekaInstanceOptions>();
87-
88-
DynamicPortAssignmentHostedService.Wire(services);
8989
}
9090

9191
private static void AddEurekaServices(IServiceCollection services)

src/Discovery/src/Eureka/PostConfigureEurekaInstanceOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ private void SetPorts(EurekaInstanceOptions options)
140140
options.IsSecurePortEnabled = true;
141141
}
142142

143-
if (options.NonSecurePort == null && options.SecurePort == null)
143+
if (options.ShouldSetPortsFromListenAddresses)
144144
{
145145
var optionsLogger = _serviceProvider.GetRequiredService<ILogger<EurekaInstanceOptions>>();
146146
ICollection<string> addresses = _configuration.GetListenAddresses();
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
#nullable enable
2+
Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.UseAspNetCoreUrls.get -> bool
3+
Steeltoe.Discovery.Eureka.Configuration.EurekaInstanceOptions.UseAspNetCoreUrls.set -> void

0 commit comments

Comments
 (0)