@@ -25,7 +25,9 @@ groups() ->
2525 get_hostname_name_from_reservation_set ,
2626 registration_support ,
2727 network_interface_sorting ,
28- private_ip_address_sorting
28+ private_ip_address_sorting ,
29+ multiple_hostname_paths_extraction ,
30+ hostname_paths_helper_functions
2931 ]},
3032 {lock , [], [
3133 lock_single_node ,
@@ -190,6 +192,130 @@ lock_local_node_not_discovered(_Config) ->
190192 Expectation = {error , " Local node " ++ atom_to_list (node ()) ++ " is not part of discovered nodes [me@host]" },
191193 ? assertEqual (Expectation , rabbit_peer_discovery_aws :lock ([me@host ])).
192194
195+ multiple_hostname_paths_extraction (_Config ) ->
196+ ok = eunit :test ({
197+ foreach ,
198+ fun on_start /0 ,
199+ fun on_finish /1 ,
200+ [{" multiple paths extraction" ,
201+ fun () ->
202+ % % Set up multiple hostname paths
203+ os :putenv (" AWS_HOSTNAME_PATHS" , " privateDnsName;privateIpAddress" ),
204+ application :set_env (rabbit , cluster_formation , [
205+ {peer_discovery_aws , [
206+ {aws_hostname_paths , [[" privateDnsName" ], [" privateIpAddress" ]]}
207+ ]}
208+ ]),
209+
210+ % % Test that multiple hostnames are extracted
211+ Expected = [" ip-10-0-16-29.eu-west-1.compute.internal" , " 10.0.16.29" ,
212+ " ip-10-0-16-31.eu-west-1.compute.internal" , " 10.0.16.31" ],
213+ Result = rabbit_peer_discovery_aws :get_hostname_name_from_reservation_set (
214+ reservation_set (), []),
215+ ? assertEqual (Expected , Result )
216+ end },
217+ {" single path fallback" ,
218+ fun () ->
219+ % % Test fallback to single path when no numbered paths configured
220+ Expected = [" ip-10-0-16-29.eu-west-1.compute.internal" ,
221+ " ip-10-0-16-31.eu-west-1.compute.internal" ],
222+ Result = rabbit_peer_discovery_aws :get_hostname_name_from_reservation_set (
223+ reservation_set (), []),
224+ ? assertEqual (Expected , Result )
225+ end },
226+ {" use_private_ip override with multiple paths" ,
227+ fun () ->
228+ % % Test that use_private_ip still works with multiple paths
229+ os :putenv (" AWS_USE_PRIVATE_IP" , " true" ),
230+ application :set_env (rabbit , cluster_formation , [
231+ {peer_discovery_aws , [
232+ {aws_hostname_paths , [[" privateDnsName" ], [" privateIpAddress" ]]},
233+ {aws_use_private_ip , true }
234+ ]}
235+ ]),
236+
237+ % % Should get private IPs for privateDnsName path, plus privateIpAddress path
238+ Expected = [" 10.0.16.29" , " 10.0.16.29" , " 10.0.16.31" , " 10.0.16.31" ],
239+ Result = rabbit_peer_discovery_aws :get_hostname_name_from_reservation_set (
240+ reservation_set (), []),
241+ % % After deduplication, should have unique IPs
242+ UniqueResult = rabbit_peer_discovery_aws :remove_duplicates_preserve_order (Result ),
243+ ExpectedUnique = [" 10.0.16.29" , " 10.0.16.31" ],
244+ ? assertEqual (ExpectedUnique , UniqueResult )
245+ end },
246+ {" no hostname paths configured - default fallback" ,
247+ fun () ->
248+ % % Test the scenario that was failing: no hostname paths configured at all
249+ % % This should fall back to default ["privateDnsName"] behavior
250+ % % Clear all hostname path configuration
251+ application :unset_env (rabbit , cluster_formation ),
252+
253+ Expected = [" ip-10-0-16-29.eu-west-1.compute.internal" ,
254+ " ip-10-0-16-31.eu-west-1.compute.internal" ],
255+ Result = rabbit_peer_discovery_aws :get_hostname_name_from_reservation_set (
256+ reservation_set (), []),
257+ ? assertEqual (Expected , Result )
258+ end },
259+ {" invalid hostname paths configuration - graceful degradation" ,
260+ fun () ->
261+ % % Test invalid configuration handling - should fall back to single path
262+ application :set_env (rabbit , cluster_formation , [
263+ {peer_discovery_aws , [
264+ {aws_hostname_paths , invalid_config }
265+ ]}
266+ ]),
267+
268+ % % Should fall back to single path behavior (same as no config)
269+ Expected = [" ip-10-0-16-29.eu-west-1.compute.internal" ,
270+ " ip-10-0-16-31.eu-west-1.compute.internal" ],
271+ Result = rabbit_peer_discovery_aws :get_hostname_name_from_reservation_set (
272+ reservation_set (), []),
273+ ? assertEqual (Expected , Result )
274+ end },
275+ {" malformed paths in configuration - graceful degradation" ,
276+ fun () ->
277+ % % Test malformed paths - should extract what it can, ignore invalid ones
278+ application :set_env (rabbit , cluster_formation , [
279+ {peer_discovery_aws , [
280+ {aws_hostname_paths , [[" privateDnsName" ], [], [" " ], [invalid_atom ]]}
281+ ]}
282+ ]),
283+
284+ % % Should extract hostnames from valid paths only
285+ % % Only ["privateDnsName"] is valid, others return empty strings and are filtered
286+ Expected = [" ip-10-0-16-29.eu-west-1.compute.internal" ,
287+ " ip-10-0-16-31.eu-west-1.compute.internal" ],
288+ Result = rabbit_peer_discovery_aws :get_hostname_name_from_reservation_set (
289+ reservation_set (), []),
290+ ? assertEqual (Expected , Result )
291+ end }]
292+ }).
293+
294+ hostname_paths_helper_functions (_Config ) ->
295+ % % Test extract_unique_hostnames
296+ Paths = [[" privateDnsName" ], [" privateIpAddress" ]],
297+ Items = [proplists :get_value (" item" , Item ) || {" item" , Item } <-
298+ proplists :get_value (" instancesSet" ,
299+ proplists :get_value (" item" , hd (reservation_set ())))],
300+
301+ Hostnames = rabbit_peer_discovery_aws :extract_unique_hostnames (Paths , Items ),
302+ ? assertEqual (2 , length (Hostnames )), % Should extract 2 unique hostnames
303+
304+ % % Test with duplicates - should be automatically removed
305+ DuplicatePaths = [[" privateDnsName" ], [" privateDnsName" ], [" privateIpAddress" ]],
306+ UniqueHostnames = rabbit_peer_discovery_aws :extract_unique_hostnames (DuplicatePaths , Items ),
307+ ? assertEqual (2 , length (UniqueHostnames )), % Should still be 2 unique hostnames
308+
309+ % % Test empty path handling - should return empty string gracefully
310+ EmptyPath = [],
311+ EmptyResult = rabbit_peer_discovery_aws :get_hostname (EmptyPath , [{" test" , " value" }]),
312+ ? assertEqual (" " , EmptyResult ),
313+
314+ % % Test invalid path handling - should return empty string gracefully
315+ InvalidPath = [invalid_atom ],
316+ InvalidResult = rabbit_peer_discovery_aws :get_hostname (InvalidPath , [{" test" , " value" }]),
317+ ? assertEqual (" " , InvalidResult ).
318+
193319% %%
194320% %% Implementation
195321% %%
@@ -203,6 +329,7 @@ on_finish(_Config) ->
203329reset () ->
204330 application :unset_env (rabbit , cluster_formation ),
205331 os :unsetenv (" AWS_HOSTNAME_PATH" ),
332+ os :unsetenv (" AWS_HOSTNAME_PATHS" ),
206333 os :unsetenv (" AWS_USE_PRIVATE_IP" ).
207334
208335reservation_set () ->
0 commit comments