diff options
-rwxr-xr-x | scripts/rabbitmq-plugins | 2 | ||||
-rwxr-xr-x | scripts/rabbitmq-plugins.bat | 10 | ||||
-rwxr-xr-x | scripts/rabbitmqctl | 5 | ||||
-rwxr-xr-x | scripts/rabbitmqctl.bat | 12 | ||||
-rw-r--r-- | src/rabbit.erl | 7 | ||||
-rw-r--r-- | src/rabbit_cli.erl | 21 | ||||
-rw-r--r-- | src/rabbit_control_main.erl | 13 | ||||
-rw-r--r-- | src/rabbit_epmd_monitor.erl | 101 | ||||
-rw-r--r-- | src/rabbit_nodes.erl | 20 |
9 files changed, 150 insertions, 41 deletions
diff --git a/scripts/rabbitmq-plugins b/scripts/rabbitmq-plugins index 29c4b0c8..22fec32f 100755 --- a/scripts/rabbitmq-plugins +++ b/scripts/rabbitmq-plugins @@ -19,11 +19,11 @@ # Non-empty defaults should be set in rabbitmq-env . `dirname $0`/rabbitmq-env +RABBITMQ_USE_LONGNAME=${RABBITMQ_USE_LONGNAME} \ exec ${ERL_DIR}erl \ -pa "${RABBITMQ_HOME}/ebin" \ -noinput \ -hidden \ - ${RABBITMQ_NAME_TYPE} rabbitmq-plugins$$ \ -boot "${CLEAN_BOOT_FILE}" \ -s rabbit_plugins_main \ -enabled_plugins_file "$RABBITMQ_ENABLED_PLUGINS_FILE" \ diff --git a/scripts/rabbitmq-plugins.bat b/scripts/rabbitmq-plugins.bat index 1ed648b0..b27a8586 100755 --- a/scripts/rabbitmq-plugins.bat +++ b/scripts/rabbitmq-plugins.bat @@ -23,14 +23,6 @@ set TDP0=%~dp0 set STAR=%*
setlocal enabledelayedexpansion
-if "!RABBITMQ_USE_LONGNAME!"=="" (
- set RABBITMQ_NAME_TYPE="-sname"
-)
-
-if "!RABBITMQ_USE_LONGNAME!"=="true" (
- set RABBITMQ_NAME_TYPE="-name"
-)
-
if "!RABBITMQ_SERVICENAME!"=="" (
set RABBITMQ_SERVICENAME=RabbitMQ
)
@@ -63,7 +55,7 @@ if "!RABBITMQ_PLUGINS_DIR!"=="" ( set RABBITMQ_PLUGINS_DIR=!TDP0!..\plugins
)
-"!ERLANG_HOME!\bin\erl.exe" -pa "!TDP0!..\ebin" -noinput -hidden !RABBITMQ_NAME_TYPE! rabbitmq-plugins!RANDOM!!TIME:~9! -s rabbit_plugins_main -enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" -plugins_dist_dir "!RABBITMQ_PLUGINS_DIR:\=/!" -nodename !RABBITMQ_NODENAME! -extra !STAR!
+"!ERLANG_HOME!\bin\erl.exe" -pa "!TDP0!..\ebin" -noinput -hidden -s rabbit_plugins_main -enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" -plugins_dist_dir "!RABBITMQ_PLUGINS_DIR:\=/!" -nodename !RABBITMQ_NODENAME! -extra !STAR!
endlocal
endlocal
diff --git a/scripts/rabbitmqctl b/scripts/rabbitmqctl index d437e251..2237275c 100755 --- a/scripts/rabbitmqctl +++ b/scripts/rabbitmqctl @@ -19,11 +19,6 @@ # Non-empty defaults should be set in rabbitmq-env . `dirname $0`/rabbitmq-env -# rabbitmqctl starts distribution itself, so we need to make sure epmd -# is running. -${ERL_DIR}erl ${RABBITMQ_NAME_TYPE} rabbitmqctl-prelaunch-$$ -noinput \ --eval 'erlang:halt().' -boot "${CLEAN_BOOT_FILE}" - # We specify Mnesia dir and sasl error logger since some actions # (e.g. forget_cluster_node --offline) require us to impersonate the # real node. diff --git a/scripts/rabbitmqctl.bat b/scripts/rabbitmqctl.bat index 6eb2530a..a3734088 100755 --- a/scripts/rabbitmqctl.bat +++ b/scripts/rabbitmqctl.bat @@ -27,14 +27,6 @@ if "!RABBITMQ_BASE!"=="" ( set RABBITMQ_BASE=!APPDATA!\RabbitMQ
)
-if "!RABBITMQ_USE_LONGNAME!"=="" (
- set RABBITMQ_NAME_TYPE="-sname"
-)
-
-if "!RABBITMQ_USE_LONGNAME!"=="true" (
- set RABBITMQ_NAME_TYPE="-name"
-)
-
if "!COMPUTERNAME!"=="" (
set COMPUTERNAME=localhost
)
@@ -63,10 +55,6 @@ if not exist "!ERLANG_HOME!\bin\erl.exe" ( exit /B
)
-rem rabbitmqctl starts distribution itself, so we need to make sure epmd
-rem is running.
-"!ERLANG_HOME!\bin\erl.exe" !RABBITMQ_NAME_TYPE! rabbitmqctl-prelaunch-!RANDOM!!TIME:~9! -noinput -eval "erlang:halt()."
-
"!ERLANG_HOME!\bin\erl.exe" ^
-pa "!TDP0!..\ebin" ^
-noinput ^
diff --git a/src/rabbit.erl b/src/rabbit.erl index 40f24efc..ba78b1ee 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -118,6 +118,13 @@ {requires, [rabbit_alarm, guid_generator]}, {enables, core_initialized}]}). +-rabbit_boot_step({rabbit_epmd_monitor, + [{description, "epmd monitor"}, + {mfa, {rabbit_sup, start_restartable_child, + [rabbit_epmd_monitor]}}, + {requires, kernel_ready}, + {enables, core_initialized}]}). + -rabbit_boot_step({core_initialized, [{description, "core initialized"}, {requires, kernel_ready}]}). diff --git a/src/rabbit_cli.erl b/src/rabbit_cli.erl index 47505b3d..cf7b6083 100644 --- a/src/rabbit_cli.erl +++ b/src/rabbit_cli.erl @@ -17,7 +17,8 @@ -module(rabbit_cli). -include("rabbit_cli.hrl"). --export([main/3, parse_arguments/4, rpc_call/4]). +-export([main/3, start_distribution/0, start_distribution/1, + parse_arguments/4, rpc_call/4]). %%---------------------------------------------------------------------------- @@ -31,6 +32,8 @@ -spec(main/3 :: (fun (([string()], string()) -> parse_result()), fun ((atom(), atom(), [any()], [any()]) -> any()), atom()) -> no_return()). +-spec(start_distribution/0 :: () -> {'ok', pid()} | {'error', any()}). +-spec(start_distribution/1 :: (string()) -> {'ok', pid()} | {'error', any()}). -spec(usage/1 :: (atom()) -> no_return()). -spec(parse_arguments/4 :: ([{atom(), [{string(), optdef()}]} | atom()], @@ -42,6 +45,8 @@ %%---------------------------------------------------------------------------- main(ParseFun, DoFun, UsageMod) -> + error_logger:tty(false), + start_distribution(), {ok, [[NodeStr|_]|_]} = init:get_argument(nodename), {Command, Opts, Args} = case ParseFun(init:get_plain_arguments(), NodeStr) of @@ -101,6 +106,20 @@ main(ParseFun, DoFun, UsageMod) -> rabbit_misc:quit(2) end. +start_distribution() -> + start_distribution(list_to_atom( + rabbit_misc:format("rabbitmq-cli-~s", [os:getpid()]))). + +start_distribution(Name) -> + rabbit_nodes:ensure_epmd(), + net_kernel:start([Name, name_type()]). + +name_type() -> + case os:getenv("RABBITMQ_USE_LONGNAME") of + "true" -> longnames; + _ -> shortnames + end. + usage(Mod) -> io:format("~s", [Mod:usage()]), rabbit_misc:quit(1). diff --git a/src/rabbit_control_main.erl b/src/rabbit_control_main.erl index bca740c6..751dbd29 100644 --- a/src/rabbit_control_main.erl +++ b/src/rabbit_control_main.erl @@ -124,7 +124,6 @@ %%---------------------------------------------------------------------------- start() -> - start_distribution(), rabbit_cli:main( fun (Args, NodeStr) -> parse_arguments(Args, NodeStr) @@ -594,28 +593,18 @@ exit_loop(Port) -> {Port, _} -> exit_loop(Port) end. -start_distribution() -> - CtlNodeName = rabbit_misc:format("rabbitmqctl-~s", [os:getpid()]), - {ok, _} = net_kernel:start([list_to_atom(CtlNodeName), name_type()]). - become(BecomeNode) -> error_logger:tty(false), ok = net_kernel:stop(), case net_adm:ping(BecomeNode) of pong -> exit({node_running, BecomeNode}); pang -> io:format(" * Impersonating node: ~s...", [BecomeNode]), - {ok, _} = net_kernel:start([BecomeNode, name_type()]), + {ok, _} = rabbit_cli:start_distribution(BecomeNode), io:format(" done~n", []), Dir = mnesia:system_info(directory), io:format(" * Mnesia directory : ~s~n", [Dir]) end. -name_type() -> - case os:getenv("RABBITMQ_USE_LONGNAME") of - "true" -> longnames; - _ -> shortnames - end. - %%---------------------------------------------------------------------------- default_if_empty(List, Default) when is_list(List) -> diff --git a/src/rabbit_epmd_monitor.erl b/src/rabbit_epmd_monitor.erl new file mode 100644 index 00000000..26155492 --- /dev/null +++ b/src/rabbit_epmd_monitor.erl @@ -0,0 +1,101 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. +%% + +-module(rabbit_epmd_monitor). + +-behaviour(gen_server). + +-export([start_link/0]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3]). + +-record(state, {timer, mod, me, host, port}). + +-define(SERVER, ?MODULE). +-define(CHECK_FREQUENCY, 60000). + +%%---------------------------------------------------------------------------- + +-ifdef(use_specs). + +-spec(start_link/0 :: () -> rabbit_types:ok_pid_or_error()). + +-endif. + +%%---------------------------------------------------------------------------- +%% It's possible for epmd to be killed out from underneath us. If that +%% happens, then obviously clustering and rabbitmqctl stop +%% working. This process checks up on epmd and restarts it / +%% re-registers us with it if it has gone away. +%% +%% How could epmd be killed? +%% +%% 1) The most popular way for this to happen is when running as a +%% Windows service. The user starts rabbitmqctl first, and this starts +%% epmd under the user's account. When they log out epmd is killed. +%% +%% 2) Some packagings of (non-RabbitMQ?) Erlang apps might do "killall +%% epmd" as a shutdown or uninstall step. +%% ---------------------------------------------------------------------------- + +start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +init([]) -> + {Me, Host} = rabbit_nodes:parts(node()), + Mod = net_kernel:epmd_module(), + {port, Port, _Version} = Mod:port_please(Me, Host), + {ok, ensure_timer(#state{mod = Mod, + me = Me, + host = Host, + port = Port})}. + +handle_call(_Request, _From, State) -> + {noreply, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(check, State) -> + check_epmd(State), + {noreply, ensure_timer(State#state{timer = undefined})}; + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%---------------------------------------------------------------------------- + +ensure_timer(State) -> + rabbit_misc:ensure_timer(State, #state.timer, ?CHECK_FREQUENCY, check). + +check_epmd(#state{mod = Mod, + me = Me, + host = Host, + port = Port}) -> + case Mod:port_please(Me, Host) of + noport -> rabbit_log:warning( + "epmd does not know us, re-registering ~s at port ~b~n", + [Me, Port]), + rabbit_nodes:ensure_epmd(), + erl_epmd:register_node(Me, Port); + _ -> ok + end. diff --git a/src/rabbit_nodes.erl b/src/rabbit_nodes.erl index 7f7fcc31..d3c0e55f 100644 --- a/src/rabbit_nodes.erl +++ b/src/rabbit_nodes.erl @@ -18,7 +18,7 @@ -export([names/1, diagnostics/1, make/1, parts/1, cookie_hash/0, is_running/2, is_process_running/2, - cluster_name/0, set_cluster_name/1]). + cluster_name/0, set_cluster_name/1, ensure_epmd/0]). -include_lib("kernel/include/inet.hrl"). @@ -41,6 +41,7 @@ -spec(is_process_running/2 :: (node(), atom()) -> boolean()). -spec(cluster_name/0 :: () -> binary()). -spec(set_cluster_name/1 :: (binary()) -> 'ok'). +-spec(ensure_epmd/0 :: () -> 'ok'). -endif. @@ -197,3 +198,20 @@ cluster_name_default() -> set_cluster_name(Name) -> rabbit_runtime_parameters:set_global(cluster_name, Name). + +ensure_epmd() -> + {ok, Root} = init:get_argument(root), + {ok, Prog} = init:get_argument(progname), + ID = random:uniform(1000000000), + Port = open_port( + {spawn_executable, filename:join([Root, "bin", Prog])}, + [{args, ["-sname", rabbit_misc:format("epmd-starter-~b", [ID]), + "-noshell", "-eval", "halt()."]}, + exit_status, stderr_to_stdout, use_stdio]), + port_shutdown_loop(Port). + +port_shutdown_loop(Port) -> + receive + {Port, {exit_status, _Rc}} -> ok; + {Port, _} -> port_shutdown_loop(Port) + end. |