diff options
Diffstat (limited to 'deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl')
-rw-r--r-- | deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl b/deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl new file mode 100644 index 0000000000..3d718438a7 --- /dev/null +++ b/deps/rabbit/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl @@ -0,0 +1,104 @@ +-module(rabbit_prelaunch_dist). + +-export([setup/1]). + +setup(#{nodename := Node, nodename_type := NameType} = Context) -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Erlang distribution =="), + rabbit_log_prelaunch:debug("Rqeuested node name: ~s (type: ~s)", + [Node, NameType]), + case node() of + nonode@nohost -> + ok = rabbit_nodes_common:ensure_epmd(), + ok = dist_port_range_check(Context), + ok = dist_port_use_check(Context), + ok = duplicate_node_check(Context), + + ok = do_setup(Context); + Node -> + rabbit_log_prelaunch:debug( + "Erlang distribution already running", []), + ok; + Unexpected -> + throw({error, {erlang_dist_running_with_unexpected_nodename, + Unexpected, Node}}) + end, + ok. + +do_setup(#{nodename := Node, nodename_type := NameType}) -> + rabbit_log_prelaunch:debug("Starting Erlang distribution", []), + case application:get_env(kernel, net_ticktime) of + {ok, Ticktime} when is_integer(Ticktime) andalso Ticktime >= 1 -> + %% The value passed to net_kernel:start/1 is the + %% "minimum transition traffic interval" as defined in + %% net_kernel:set_net_ticktime/1. + MTTI = Ticktime * 1000 div 4, + {ok, _} = net_kernel:start([Node, NameType, MTTI]), + ok; + _ -> + {ok, _} = net_kernel:start([Node, NameType]), + ok + end, + ok. + +%% Check whether a node with the same name is already running +duplicate_node_check(#{split_nodename := {NodeName, NodeHost}}) -> + rabbit_log_prelaunch:debug( + "Checking if node name ~s is already used", [NodeName]), + PrelaunchName = rabbit_nodes_common:make( + {NodeName ++ "_prelaunch_" ++ os:getpid(), + "localhost"}), + {ok, _} = net_kernel:start([PrelaunchName, shortnames]), + case rabbit_nodes_common:names(NodeHost) of + {ok, NamePorts} -> + case proplists:is_defined(NodeName, NamePorts) of + true -> + throw({error, {duplicate_node_name, NodeName, NodeHost}}); + false -> + ok = net_kernel:stop(), + ok + end; + {error, EpmdReason} -> + throw({error, {epmd_error, NodeHost, EpmdReason}}) + end. + +dist_port_range_check(#{erlang_dist_tcp_port := DistTcpPort}) -> + rabbit_log_prelaunch:debug( + "Checking if TCP port ~b is valid", [DistTcpPort]), + case DistTcpPort of + _ when DistTcpPort < 1 orelse DistTcpPort > 65535 -> + throw({error, {invalid_dist_port_range, DistTcpPort}}); + _ -> + ok + end. + +dist_port_use_check(#{split_nodename := {_, NodeHost}, + erlang_dist_tcp_port := DistTcpPort}) -> + rabbit_log_prelaunch:debug( + "Checking if TCP port ~b is available", [DistTcpPort]), + dist_port_use_check_ipv4(NodeHost, DistTcpPort). + +dist_port_use_check_ipv4(NodeHost, Port) -> + case gen_tcp:listen(Port, [inet, {reuseaddr, true}]) of + {ok, Sock} -> gen_tcp:close(Sock); + {error, einval} -> dist_port_use_check_ipv6(NodeHost, Port); + {error, _} -> dist_port_use_check_fail(Port, NodeHost) + end. + +dist_port_use_check_ipv6(NodeHost, Port) -> + case gen_tcp:listen(Port, [inet6, {reuseaddr, true}]) of + {ok, Sock} -> gen_tcp:close(Sock); + {error, _} -> dist_port_use_check_fail(Port, NodeHost) + end. + +-spec dist_port_use_check_fail(non_neg_integer(), string()) -> + no_return(). + +dist_port_use_check_fail(Port, Host) -> + {ok, Names} = rabbit_nodes_common:names(Host), + case [N || {N, P} <- Names, P =:= Port] of + [] -> + throw({error, {dist_port_already_used, Port, not_erlang, Host}}); + [Name] -> + throw({error, {dist_port_already_used, Port, Name, Host}}) + end. |