From df658317ee0209afe21aac3cfe8e49e2b3d04f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-S=C3=A9bastien=20P=C3=A9dron?= Date: Thu, 13 Jun 2024 14:57:46 +0200 Subject: [PATCH] peer_discovery_tmp_hidden_node_SUITE: Use IP address to simulate a long node name [Why] The `longnames`-based testcase depends on a copnfigured FQDN. Buildbuddy hosts were incorrectly configured and were lacking one. As a workaround, `/etc/hosts` was modified to add an FQDN. We don't use Buildbuddy anymore, but the problem also appeared on team members' Broadcom-managed laptops (also having an incomplete network configuration). More importantly, GitHub workers seem to have the same problem, but randomly! At this point, we can't rely on the host's correct network configuration. [How] The testsuite is modified to use a hard-coded IP address, 127.0.0.1, to simulate a long Erlang node name (i.e. it has dots). --- .../peer_discovery_tmp_hidden_node_SUITE.erl | 133 +++--------------- 1 file changed, 20 insertions(+), 113 deletions(-) diff --git a/deps/rabbit/test/peer_discovery_tmp_hidden_node_SUITE.erl b/deps/rabbit/test/peer_discovery_tmp_hidden_node_SUITE.erl index a4dde9ab8e66..61951a1fcd43 100644 --- a/deps/rabbit/test/peer_discovery_tmp_hidden_node_SUITE.erl +++ b/deps/rabbit/test/peer_discovery_tmp_hidden_node_SUITE.erl @@ -220,41 +220,34 @@ start_test_nodes(Testcase, NodeNumber, NodeCount, PeerOptions, Peers) when NodeNumber =< NodeCount -> PeerName0 = rabbit_misc:format("~s-~b", [Testcase, NodeNumber]), PeerOptions1 = PeerOptions#{name => PeerName0}, - ct:pal("Starting peer with options: ~p", [PeerOptions1]), - case catch peer:start(PeerOptions1) of + PeerOptions2 = case PeerOptions1 of + #{host := _} -> + PeerOptions1; + #{longnames := true} -> + %% To simulate Erlang long node names, we use a + %% hard-coded IP address that is likely to exist. + %% + %% We can't rely on the host proper network + %% configuration because it appears that several + %% hosts are half-configured (at least some random + %% GitHub workers and Broadcom-managed OSX laptops + %% in the team). + PeerOptions1#{host => "127.0.0.1"}; + _ -> + PeerOptions1 + end, + ct:pal("Starting peer with options: ~p", [PeerOptions2]), + case catch peer:start(PeerOptions2) of {ok, PeerPid, PeerName} -> ct:pal("Configuring peer '~ts'", [PeerName]), - setup_test_node(PeerPid, PeerOptions1), + setup_test_node(PeerPid, PeerOptions2), Peers1 = Peers#{PeerName => PeerPid}, start_test_nodes( Testcase, NodeNumber + 1, NodeCount, PeerOptions, Peers1); - Error1 when not is_map_key(host, PeerOptions1) -> - ct:pal("Failed to started peer node:~n" - "Options: ~p~n" - "Error: ~p", [PeerOptions1, Error1]), - %% At least when running from a Buildbuddy CI worker, the network - %% configuration is incomplete and the host lacks an FQDN. This - %% breaks the start of an Erlang node with long names. - %% - %% To work around that, we mess with the network configuration (the - %% Erlang node runs as root) and try to determine a hostname we can - %% use. We then try again to start the node. - case determine_hostname(PeerOptions1) of - {ok, Host} -> - PeerOptions2 = PeerOptions1#{host => Host}, - start_test_nodes( - Testcase, NodeNumber, NodeCount, PeerOptions2, Peers); - {error, _} = Error2 -> - ct:pal("Failed to determine a usable hostname:~n" - "Options: ~p~n" - "Error: ~p", [PeerOptions1, Error2]), - stop_test_nodes(Peers), - erlang:throw(Error2) - end; Error -> ct:pal("Failed to started peer node:~n" "Options: ~p~n" - "Error: ~p", [PeerOptions1, Error]), + "Error: ~p", [PeerOptions2, Error]), stop_test_nodes(Peers), erlang:throw(Error) end; @@ -262,92 +255,6 @@ start_test_nodes(_Testcase, _NodeNumber, _Count, _PeerOptions, Peers) -> ct:pal("Peers: ~p", [Peers]), Peers. -determine_hostname(PeerOptions) -> - %% Please wear eye protection glasses to read what's next! - %% - %% The Buildbuddy CI worker network configuration lacks an FQDN and we need - %% one to start an Erlang node with a long name. To work around this, we - %% modify `/etc/hosts' to add an FQDN for 127.0.0.1 and ::1. - %% - %% 1. We read the existing file - %% 2. We modify it to add the FQDN - %% 3. We write the modified file - %% 4. We put a coin in the swear jar - HostsFilename = "/etc/hosts", - case file:read_file(HostsFilename) of - {ok, HostsFile} -> - HostsFile1 = re:replace( - HostsFile, - "^(127\\.0\\.0\\.1|::1)\\s+.*", - "& localhost.my.domain", - [{return, binary}, multiline, global]), - ct:pal( - "Changing ~s from:~n" - "---8<---~n" - "~s" - "---8<---~n" - "to:~n" - "---8<---~n" - "~s" - "---8<---~n", - [HostsFilename, HostsFile, HostsFile1]), - case file:write_file(HostsFilename, HostsFile1) of - ok -> determine_hostname1(PeerOptions); - {error, _} = Error -> Error - end; - {error, _} = Error -> - Error - end. - -determine_hostname1(PeerOptions) -> - %% Now that we proudly have an FQDN, we query the IP - %% addresses and get the hostname(s) associated with each. - %% - %% In the end, we return the first hostname that matches - %% the short/long name criteria. - case inet:getifaddrs() of - {ok, IFaces} -> - ct:pal("Network interfaces: ~p", [IFaces]), - IPv4Addrs = [IPv4Addr - || {_Name, Props} <- IFaces, - {addr, IPv4Addr} <- Props, - is_tuple(IPv4Addr) andalso size(IPv4Addr) =:= 4], - ct:pal("IPv4 addresses: ~p", [IPv4Addrs]), - determine_hostname2(IPv4Addrs, PeerOptions); - {error, _} = Error -> - Error - end. - -determine_hostname2([IPv4Addr | Rest], PeerOptions) -> - WantFQDN = maps:get(longnames, PeerOptions, false), - case inet:gethostbyaddr(IPv4Addr) of - {ok, #hostent{h_name = FQDN, h_aliases = ShortDNs}} -> - AllDNs = [FQDN | ShortDNs], - ct:pal( - "All domain names for IPv4 address ~p: ~p", - [IPv4Addr, AllDNs]), - ValidDNs = lists:filter( - fun(DN) -> - lists:member($., DN) =:= WantFQDN - end, AllDNs), - ct:pal( - "Valid domain names for IPv4 address ~p: ~p", - [IPv4Addr, ValidDNs]), - case ValidDNs of - [DN | _] -> - {ok, DN}; - [] -> - ct:pal( - "No valid hostnames found for IPv4 ~p: ~p", - [IPv4Addr, AllDNs]), - determine_hostname2(Rest, PeerOptions) - end; - {error, _} = Error -> - Error - end; -determine_hostname2([], _PeerOptions) -> - {error, no_valid_hostnames_found}. - setup_test_node(PeerPid, PeerOptions) -> peer:call(PeerPid, ?MODULE, do_setup_test_node, [PeerOptions]).