diff options
| author | Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com> | 2019-05-15 16:27:51 +0200 |
|---|---|---|
| committer | Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com> | 2019-12-11 17:48:49 +0100 |
| commit | 68c30553ccf306325a64b1fe6069e6bcc9c26b41 (patch) | |
| tree | 1026b9693d79f723c474c3de2e782215fb002926 | |
| parent | 5e6043ac59abbafd62bae2d3721a01ed232fc5f3 (diff) | |
| download | rabbitmq-server-git-68c30553ccf306325a64b1fe6069e6bcc9c26b41.tar.gz | |
Move most of shell scripts to Erlang code
A large part of the rabbitmq-server(8) and CLI scripts, both
Bourne-shell and Windows Batch versions, was moved to Erlang code and
the RabbitMQ startup procedure was reorganized to be closer to a regular
Erlang application.
A new application called `rabbitmq_prelaunch` is responsible for:
1. Querying the environment variables to initialize important
variables (using the new `rabbit_env` module in rabbitmq-common).
2. Checking the compatibility with the Erlang/OTP runtime.
3. Configuring Erlang distribution.
5. Writing the PID file.
The application is started early (i.e. it is started before `rabbit`).
The `rabbit` application runs the second half of the prelaunch sequence
at the beginning of the application `start()` function. This second
phase is responsible for the following steps:
1. Preparing the feature flags registry.
2. Reading and validating the configuration.
3. Configuring logging.
4. Running the various cluster checks.
In addition to this prelaunch sequence, the `rabbit` application start
procedure ends with a "postlaunch" sequence which takes care of
starting enabled plugins.
Thanks to this, RabbitMQ can be started with `application:start(rabbit)`
as any other Erlang application. The only caveats are:
* Mnesia must be stopped at the time `rabbit_prelaunch` is started,
and must remain stopped when `rabbit` is started, to allow the
Erlang distribution setup and cluster checks. `rabbit` takes care of
starting Mnesia.
* Likewise for Ra, because it relies on the `ra` application
environment to be configured.
Transitioning from scripts to Erlang code has the following benefits:
* RabbitMQ start behavior should be identical between Unix and
Windows. Also, features should be on par now. For instance, RabbitMQ
now writes a PID file on Windows, like it always did on Unix-based
systems.
* The difference between published packages and a development
environment are greatly reduced. In fact, we removed all the "if
this is a dev working copy, then ..." blocks.
As part of that, the `rabbit` application is now treated like its
plugins: it is packaged as an `.ez` archive and written to the
`plugins` directory (even though it is not technically a plugin).
Also in a development copy, the CLI is copied to the top-level
project. So when testing a plugin for instance, the CLI to use is
`sbin/rabbitmqctl` in the current directory, not the master copy in
`rabbit/scripts`.
* As a consequence of the previous two points, maintaining and testing
on Windows is now made easy. It should even be possible to setup CI
on Windows.
* There are less issues with paths containing non-US-ASCII characters,
which can happen on Windows because RabbitMQ stores its data in user
directories by default.
This process brings at least one more benefit: we now have early logging
during this prelaunch phase, which eases diagnostics and debugging.
There are also behavior changes:
* The new format configuration files used to be converted to an
Erlang-term-based file by the Cuttlefish CLI. To do that,
configuration schemas were copied to a temporary directory and the
generated configuration file was written to RabbitMQ data directory.
Now, Cuttlefish is used as a library: everything happens in memory.
No schemas are copied, no generated configuration is written to
disk.
* The PID file is removed when the Erlang VM exits.
* The `rabbit_config` module was trimmed significantly because most of
the configuration handling is done in `rabbit_prelaunch_conf` now.
* The RabbitMQ nodename does not appear on the command line, therefore
it is missing from ps(1) and top(1) output.
* The `rabbit:start()` function will probably behave differently in
some ways because it defers everything to the Erlang application
controller (instead of reimplementing it).
41 files changed, 1970 insertions, 2296 deletions
diff --git a/.gitignore b/.gitignore index 42cc7ad1cc..7dfe376dce 100644 --- a/.gitignore +++ b/.gitignore @@ -11,13 +11,17 @@ MnesiaCore.* /debug/ /doc/ /ebin/ +/escript +/escript.lock /etc/ /logs/ /plugins/ +/plugins.lock /test/ct.cover.spec /test/config_schema_SUITE_data/schema/** /xrefr -/escript +/sbin/ +/sbin.lock rabbit.d # Generated documentation. @@ -133,11 +133,19 @@ define PROJECT_ENV ] endef -LOCAL_DEPS = sasl mnesia os_mon inets compiler public_key crypto ssl syntax_tools xmerl +# With Erlang.mk default behavior, the value of `$(APPS_DIR)` is always +# relative to the top-level executed Makefile. In our case, it could be +# a plugin for instance. However, the rabbitmq_prelaunch application is +# in this repository, not the plugin's. That's why we need to override +# this value here. +APPS_DIR := $(CURDIR)/apps + +LOCAL_DEPS = sasl rabbitmq_prelaunch os_mon inets compiler public_key crypto ssl syntax_tools xmerl BUILD_DEPS = rabbitmq_cli syslog -DEPS = ranch lager rabbit_common ra sysmon_handler stdout_formatter recon observer_cli +DEPS = cuttlefish ranch lager rabbit_common ra sysmon_handler stdout_formatter recon observer_cli TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client meck proper +dep_cuttlefish = hex 2.2.0 dep_syslog = git https://github.com/schlagert/syslog 3.4.5 define usage_xml_to_erl @@ -164,6 +172,9 @@ ERLANG_MK_COMMIT = rabbitmq-tmp include rabbitmq-components.mk include erlang.mk +# See above why we mess with `$(APPS_DIR)`. +unexport APPS_DIR + ifeq ($(strip $(BATS)),) BATS := $(ERLANG_MK_TMP)/bats/bin/bats endif @@ -240,20 +251,6 @@ USE_PROPER_QC := $(shell $(ERL) -eval 'io:format({module, proper} =:= code:ensur RMQ_ERLC_OPTS += $(if $(filter true,$(USE_PROPER_QC)),-Duse_proper_qc) endif -.PHONY: copy-escripts clean-extra-sources clean-escripts - -CLI_ESCRIPTS_DIR = escript - -copy-escripts: - $(gen_verbose) $(MAKE) -C $(DEPS_DIR)/rabbitmq_cli install \ - PREFIX="$(abspath $(CLI_ESCRIPTS_DIR))" \ - DESTDIR= - -clean:: clean-escripts - -clean-escripts: - $(gen_verbose) rm -rf "$(CLI_ESCRIPTS_DIR)" - # -------------------------------------------------------------------- # Documentation. # -------------------------------------------------------------------- @@ -297,5 +294,3 @@ distclean:: distclean-manpages distclean-manpages:: $(gen_verbose) rm -f $(WEB_MANPAGES) - -app-build: copy-escripts diff --git a/apps/rabbitmq_prelaunch/.gitignore b/apps/rabbitmq_prelaunch/.gitignore new file mode 100644 index 0000000000..adca0d7655 --- /dev/null +++ b/apps/rabbitmq_prelaunch/.gitignore @@ -0,0 +1,12 @@ +*~ +.sw? +.*.sw? +*.beam +*.coverdata +/ebin/ +/.erlang.mk/ +/rabbitmq_prelaunch.d +/xrefr + +# Dialyzer +*.plt diff --git a/apps/rabbitmq_prelaunch/Makefile b/apps/rabbitmq_prelaunch/Makefile new file mode 100644 index 0000000000..572f7703d4 --- /dev/null +++ b/apps/rabbitmq_prelaunch/Makefile @@ -0,0 +1,11 @@ +PROJECT = rabbitmq_prelaunch +PROJECT_DESCRIPTION = RabbitMQ prelaunch setup +PROJECT_VERSION = 1.0.0 +PROJECT_MOD = rabbit_prelaunch_app + +DEPS = rabbit_common lager + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-build.mk + +include ../../rabbitmq-components.mk +include ../../erlang.mk diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl new file mode 100644 index 0000000000..5c3d56cd50 --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch.erl @@ -0,0 +1,274 @@ +-module(rabbit_prelaunch). + +-include_lib("eunit/include/eunit.hrl"). + +-export([run_prelaunch_first_phase/0, + assert_mnesia_is_stopped/0, + get_context/0, + get_boot_state/0, + set_boot_state/1, + is_boot_state_reached/1, + wait_for_boot_state/1, + wait_for_boot_state/2, + get_stop_reason/0, + set_stop_reason/1, + clear_stop_reason/0, + is_initial_pass/0, + initial_pass_finished/0, + shutdown_func/1]). + +-define(PT_KEY_CONTEXT, {?MODULE, context}). +-define(PT_KEY_BOOT_STATE, {?MODULE, boot_state}). +-define(PT_KEY_INITIAL_PASS, {?MODULE, initial_pass_finished}). +-define(PT_KEY_SHUTDOWN_FUNC, {?MODULE, chained_shutdown_func}). +-define(PT_KEY_STOP_REASON, {?MODULE, stop_reason}). + +run_prelaunch_first_phase() -> + try + do_run() + catch + throw:{error, _} = Error -> + rabbit_prelaunch_errors:log_error(Error), + set_stop_reason(Error), + set_boot_state(stopped), + Error; + Class:Exception:Stacktrace -> + rabbit_prelaunch_errors:log_exception( + Class, Exception, Stacktrace), + Error = {error, Exception}, + set_stop_reason(Error), + set_boot_state(stopped), + Error + end. + +do_run() -> + %% Indicate RabbitMQ is booting. + clear_stop_reason(), + set_boot_state(booting), + + %% Configure dbg if requested. + rabbit_prelaunch_early_logging:enable_quick_dbg(rabbit_env:dbg_config()), + + %% We assert Mnesia is stopped before we run the prelaunch + %% phases. + %% + %% We need this because our cluster consistency check (in the second + %% phase) depends on Mnesia not being started before it has a chance + %% to run. + %% + %% Also, in the initial pass, we don't want Mnesia to run before + %% Erlang distribution is configured. + assert_mnesia_is_stopped(), + + %% Get informations to setup logging. + Context0 = rabbit_env:get_context_before_logging_init(), + ?assertMatch(#{}, Context0), + + %% Setup logging for the prelaunch phase. + ok = rabbit_prelaunch_early_logging:setup_early_logging(Context0, true), + + IsInitialPass = is_initial_pass(), + case IsInitialPass of + true -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug( + "== Prelaunch phase [1/2] (initial pass) =="), + rabbit_log_prelaunch:debug(""); + false -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Prelaunch phase [1/2] =="), + rabbit_log_prelaunch:debug("") + end, + rabbit_env:log_process_env(), + + %% Load rabbitmq-env.conf, redo logging setup and continue. + Context1 = rabbit_env:get_context_after_logging_init(Context0), + ?assertMatch(#{}, Context1), + ok = rabbit_prelaunch_early_logging:setup_early_logging(Context1, true), + rabbit_env:log_process_env(), + + %% Complete context now that we have the final environment loaded. + Context2 = rabbit_env:get_context_after_reloading_env(Context1), + ?assertMatch(#{}, Context2), + store_context(Context2), + rabbit_env:log_context(Context2), + ok = setup_shutdown_func(), + + Context = Context2#{initial_pass => IsInitialPass}, + + rabbit_env:context_to_code_path(Context), + rabbit_env:context_to_app_env_vars(Context), + + %% 1. Erlang/OTP compatibility check. + ok = rabbit_prelaunch_erlang_compat:check(Context), + + %% 2. Erlang distribution check + start. + ok = rabbit_prelaunch_dist:setup(Context), + + %% 3. Write PID file. + rabbit_log_prelaunch:debug(""), + _ = write_pid_file(Context), + ignore. + +assert_mnesia_is_stopped() -> + ?assertNot(lists:keymember(mnesia, 1, application:which_applications())). + +store_context(Context) when is_map(Context) -> + persistent_term:put(?PT_KEY_CONTEXT, Context). + +get_context() -> + case persistent_term:get(?PT_KEY_CONTEXT, undefined) of + undefined -> undefined; + Context -> Context#{initial_pass => is_initial_pass()} + end. + +get_boot_state() -> + persistent_term:get(?PT_KEY_BOOT_STATE, stopped). + +set_boot_state(stopped) -> + rabbit_log_prelaunch:debug("Change boot state to `stopped`"), + persistent_term:erase(?PT_KEY_BOOT_STATE); +set_boot_state(BootState) -> + rabbit_log_prelaunch:debug("Change boot state to `~s`", [BootState]), + ?assert(is_boot_state_valid(BootState)), + persistent_term:put(?PT_KEY_BOOT_STATE, BootState). + +wait_for_boot_state(BootState) -> + wait_for_boot_state(BootState, infinity). + +wait_for_boot_state(BootState, Timeout) -> + ?assert(is_boot_state_valid(BootState)), + wait_for_boot_state1(BootState, Timeout). + +wait_for_boot_state1(BootState, infinity = Timeout) -> + case is_boot_state_reached(BootState) of + true -> ok; + false -> wait_for_boot_state1(BootState, Timeout) + end; +wait_for_boot_state1(BootState, Timeout) + when is_integer(Timeout) andalso Timeout >= 0 -> + case is_boot_state_reached(BootState) of + true -> ok; + false -> Wait = 200, + timer:sleep(Wait), + wait_for_boot_state1(BootState, Timeout - Wait) + end; +wait_for_boot_state1(_, _) -> + {error, timeout}. + +boot_state_idx(stopped) -> 0; +boot_state_idx(booting) -> 1; +boot_state_idx(ready) -> 2; +boot_state_idx(stopping) -> 3; +boot_state_idx(_) -> undefined. + +is_boot_state_valid(BootState) -> + is_integer(boot_state_idx(BootState)). + +is_boot_state_reached(TargetBootState) -> + is_boot_state_reached(get_boot_state(), TargetBootState). + +is_boot_state_reached(CurrentBootState, CurrentBootState) -> + true; +is_boot_state_reached(stopping, stopped) -> + false; +is_boot_state_reached(_CurrentBootState, stopped) -> + true; +is_boot_state_reached(stopped, _TargetBootState) -> + true; +is_boot_state_reached(CurrentBootState, TargetBootState) -> + boot_state_idx(TargetBootState) =< boot_state_idx(CurrentBootState). + +get_stop_reason() -> + persistent_term:get(?PT_KEY_STOP_REASON, undefined). + +set_stop_reason(Reason) -> + case get_stop_reason() of + undefined -> + rabbit_log_prelaunch:debug("Set stop reason to: ~p", [Reason]), + persistent_term:put(?PT_KEY_STOP_REASON, Reason); + _ -> + ok + end. + +clear_stop_reason() -> + persistent_term:erase(?PT_KEY_STOP_REASON). + +is_initial_pass() -> + not persistent_term:get(?PT_KEY_INITIAL_PASS, false). + +initial_pass_finished() -> + persistent_term:put(?PT_KEY_INITIAL_PASS, true). + +setup_shutdown_func() -> + ThisMod = ?MODULE, + ThisFunc = shutdown_func, + ExistingShutdownFunc = application:get_env(kernel, shutdown_func), + case ExistingShutdownFunc of + {ok, {ThisMod, ThisFunc}} -> + ok; + {ok, {ExistingMod, ExistingFunc}} -> + rabbit_log_prelaunch:debug( + "Setting up kernel shutdown function: ~s:~s/1 " + "(chained with ~s:~s/1)", + [ThisMod, ThisFunc, ExistingMod, ExistingFunc]), + ok = persistent_term:put( + ?PT_KEY_SHUTDOWN_FUNC, + ExistingShutdownFunc), + ok = record_kernel_shutdown_func(ThisMod, ThisFunc); + _ -> + rabbit_log_prelaunch:debug( + "Setting up kernel shutdown function: ~s:~s/1", + [ThisMod, ThisFunc]), + ok = record_kernel_shutdown_func(ThisMod, ThisFunc) + end. + +record_kernel_shutdown_func(Mod, Func) -> + application:set_env( + kernel, shutdown_func, {Mod, Func}, + [{persistent, true}]). + +shutdown_func(Reason) -> + rabbit_log_prelaunch:debug( + "Running ~s:shutdown_func() as part of `kernel` shutdown", [?MODULE]), + Context = get_context(), + remove_pid_file(Context), + ChainedShutdownFunc = persistent_term:get( + ?PT_KEY_SHUTDOWN_FUNC, + undefined), + case ChainedShutdownFunc of + {ChainedMod, ChainedFunc} -> ChainedMod:ChainedFunc(Reason); + _ -> ok + end. + +write_pid_file(#{pid_file := PidFile}) -> + rabbit_log_prelaunch:debug("Writing PID file: ~s", [PidFile]), + case filelib:ensure_dir(PidFile) of + ok -> + OSPid = os:getpid(), + case file:write_file(PidFile, OSPid) of + ok -> + ok; + {error, Reason} = Error -> + rabbit_log_prelaunch:warning( + "Failed to write PID file \"~s\": ~s", + [PidFile, file:format_error(Reason)]), + Error + end; + {error, Reason} = Error -> + rabbit_log_prelaunch:warning( + "Failed to create PID file \"~s\" directory: ~s", + [PidFile, file:format_error(Reason)]), + Error + end; +write_pid_file(_) -> + ok. + +remove_pid_file(#{pid_file := PidFile, keep_pid_file_on_exit := true}) -> + rabbit_log_prelaunch:debug("Keeping PID file: ~s", [PidFile]), + ok; +remove_pid_file(#{pid_file := PidFile}) -> + rabbit_log_prelaunch:debug("Deleting PID file: ~s", [PidFile]), + _ = file:delete(PidFile); +remove_pid_file(_) -> + ok. diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_app.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_app.erl new file mode 100644 index 0000000000..cef7f05e77 --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_app.erl @@ -0,0 +1,11 @@ +-module(rabbit_prelaunch_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + rabbit_prelaunch_sup:start_link(). + +stop(_State) -> + ok. diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl new file mode 100644 index 0000000000..70f99feba6 --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_dist.erl @@ -0,0 +1,102 @@ +-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, _} = net_kernel:start([Node, NameType]) + 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:make( + {NodeName ++ "_prelaunch_" ++ os:getpid(), + "localhost"}), + {ok, _} = net_kernel:start([PrelaunchName, shortnames]), + case rabbit_nodes:names(NodeHost) of + {ok, NamePorts} -> + case proplists:is_defined(NodeName, NamePorts) of + true -> + throw({error, {duplicate_node_name, NodeName, NodeHost}}); + false -> + 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: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. diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl new file mode 100644 index 0000000000..66883e501b --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_early_logging.erl @@ -0,0 +1,61 @@ +-module(rabbit_prelaunch_early_logging). + +-export([setup_early_logging/2, + enable_quick_dbg/1, + use_colored_logging/0, + use_colored_logging/1]). + +-define(SINK, rabbit_log_prelaunch_lager_event). + +setup_early_logging(#{log_levels := undefined} = Context, + LagerEventToStdout) -> + setup_early_logging(Context#{log_levels => get_default_log_level()}, + LagerEventToStdout); +setup_early_logging(Context, LagerEventToStdout) -> + case lists:member(?SINK, lager:list_all_sinks()) of + true -> ok; + false -> do_setup_early_logging(Context, LagerEventToStdout) + end. + +get_default_log_level() -> + #{"prelaunch" => warning}. + +do_setup_early_logging(#{log_levels := LogLevels} = Context, + LagerEventToStdout) -> + LogLevel = case LogLevels of + #{"prelaunch" := Level} -> Level; + #{global := Level} -> Level; + _ -> warning + end, + Colored = use_colored_logging(Context), + ConsoleBackend = lager_console_backend, + ConsoleOptions = [{level, LogLevel}], + application:set_env(lager, colored, Colored), + case LagerEventToStdout of + true -> + lager_app:start_handler( + lager_event, ConsoleBackend, ConsoleOptions); + false -> + ok + end, + lager_app:configure_sink( + ?SINK, + [{handlers, [{ConsoleBackend, ConsoleOptions}]}]), + ok. + +use_colored_logging() -> + use_colored_logging(rabbit_prelaunch:get_context()). + +use_colored_logging(#{log_levels := #{color := true}, + output_supports_colors := true}) -> + true; +use_colored_logging(_) -> + false. + +enable_quick_dbg(#{dbg_output := Output, dbg_mods := Mods}) -> + case Output of + stdout -> {ok, _} = dbg:tracer(); + _ -> {ok, _} = dbg:tracer(port, dbg:trace_port(file, Output)) + end, + {ok, _} = dbg:p(all, c), + lists:foreach(fun(M) -> {ok, _} = dbg:tp(M, cx) end, Mods). diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_erlang_compat.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_erlang_compat.erl new file mode 100644 index 0000000000..1e8fe2690d --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_erlang_compat.erl @@ -0,0 +1,47 @@ +-module(rabbit_prelaunch_erlang_compat). + +-export([check/1]). + +-define(OTP_MINIMUM, "21.3"). +-define(ERTS_MINIMUM, "10.3"). + +check(_Context) -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Erlang/OTP compatibility check =="), + + ERTSVer = erlang:system_info(version), + OTPRel = rabbit_misc:otp_release(), + rabbit_log_prelaunch:debug( + "Requiring: Erlang/OTP ~s (ERTS ~s)", [?OTP_MINIMUM, ?ERTS_MINIMUM]), + rabbit_log_prelaunch:debug( + "Running: Erlang/OTP ~s (ERTS ~s)", [OTPRel, ERTSVer]), + + case rabbit_misc:version_compare(?ERTS_MINIMUM, ERTSVer, lte) of + true when ?ERTS_MINIMUM =/= ERTSVer -> + rabbit_log_prelaunch:debug( + "Erlang/OTP version requirement satisfied"), + ok; + true when ?ERTS_MINIMUM =:= ERTSVer andalso ?OTP_MINIMUM =< OTPRel -> + %% When a critical regression or bug is found, a new OTP + %% release can be published without changing the ERTS + %% version. For instance, this is the case with R16B03 and + %% R16B03-1. + %% + %% In this case, we compare the release versions + %% alphabetically. + ok; + _ -> + Msg = + "This RabbitMQ version cannot run on Erlang ~s (erts ~s): " + "minimum required version is ~s (erts ~s)", + Args = [OTPRel, ERTSVer, ?OTP_MINIMUM, ?ERTS_MINIMUM], + rabbit_log_prelaunch:error(Msg, Args), + + %% Also print to stderr to make this more visible + io:format(standard_error, "Error: " ++ Msg ++ "~n", Args), + + Msg2 = rabbit_misc:format( + "Erlang ~s or later is required, started on ~s", + [?OTP_MINIMUM, OTPRel]), + throw({error, {erlang_version_too_old, Msg2}}) + end. diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_errors.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_errors.erl new file mode 100644 index 0000000000..46392ea499 --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_errors.erl @@ -0,0 +1,109 @@ +-module(rabbit_prelaunch_errors). + +-export([format_error/1, + format_exception/3, + log_error/1, + log_exception/3]). + +-define(BOOT_FAILED_HEADER, + "\n" + "BOOT FAILED\n" + "===========\n"). + +-define(BOOT_FAILED_FOOTER, + "\n"). + +log_error(Error) -> + Message = format_error(Error), + log_message(Message). + +format_error({error, {duplicate_node_name, NodeName, NodeHost}}) -> + rabbit_misc:format( + "ERROR: node with name ~p already running on ~p", + [NodeName, NodeHost]); +format_error({error, {epmd_error, NodeHost, EpmdReason}}) -> + rabbit_misc:format( + "ERROR: epmd error for host ~s: ~s", + [NodeHost, rabbit_misc:format_inet_error(EpmdReason)]); +format_error({error, {invalid_dist_port_range, DistTcpPort}}) -> + rabbit_misc:format( + "Invalid Erlang distribution TCP port: ~b", [DistTcpPort]); +format_error({error, {dist_port_already_used, Port, not_erlang, Host}}) -> + rabbit_misc:format( + "ERROR: distribution port ~b in use on ~s " + "(by non-Erlang process?)", [Port, Host]); +format_error({error, {dist_port_already_used, Port, Name, Host}}) -> + rabbit_misc:format( + "ERROR: distribution port ~b in use by ~s@~s", [Port, Name, Host]); +format_error({error, {erlang_dist_running_with_unexpected_nodename, + Unexpected, Node}}) -> + rabbit_misc:format( + "Erlang distribution running with another node name (~s) " + "than the configured one (~s)", + [Unexpected, Node]); +format_error({bad_config_entry_decoder, missing_passphrase}) -> + rabbit_misc:format( + "Missing passphrase or missing passphrase read method in " + "`config_entry_decoder`"); +format_error({config_decryption_error, {key, Key}, _Msg}) -> + rabbit_misc:format( + "Error while decrypting key '~p'. Please check encrypted value, " + "passphrase, and encryption configuration~n", + [Key]); +format_error({error, {timeout_waiting_for_tables, AllNodes, _}}) -> + Suffix = + "~nBACKGROUND~n==========~n~n" + "This cluster node was shut down while other nodes were still running.~n" + "To avoid losing data, you should start the other nodes first, then~n" + "start this one. To force this node to start, first invoke~n" + "\"rabbitmqctl force_boot\". If you do so, any changes made on other~n" + "cluster nodes after this one was shut down may be lost.", + {Message, Nodes} = + case AllNodes -- [node()] of + [] -> {rabbit_misc:format( + "Timeout contacting cluster nodes. Since RabbitMQ was" + " shut down forcefully~nit cannot determine which nodes" + " are timing out.~n" ++ Suffix, []), + []}; + Ns -> {rabbit_misc:format( + "Timeout contacting cluster nodes: ~p.~n" ++ Suffix, + [Ns]), + Ns} + end, + Message ++ "\n" ++ rabbit_nodes_common:diagnostics(Nodes); +format_error({error, {cannot_log_to_file, unknown, Reason}}) -> + rabbit_misc:format( + "failed to initialised logger: ~p~n", + [Reason]); +format_error({error, {cannot_log_to_file, LogFile, + {cannot_create_parent_dirs, _, Reason}}}) -> + rabbit_misc:format( + "failed to create parent directory for log file at '~s', reason: ~s~n", + [LogFile, file:format_error(Reason)]); +format_error({error, {cannot_log_to_file, LogFile, Reason}}) -> + rabbit_misc:format( + "failed to open log file at '~s', reason: ~s", + [LogFile, file:format_error(Reason)]); +format_error(Error) -> + rabbit_misc:format("Error during startup: ~p", [Error]). + +log_exception(Class, Exception, Stacktrace) -> + Message = format_exception(Class, Exception, Stacktrace), + log_message(Message). + +format_exception(Class, Exception, Stacktrace) -> + rabbit_misc:format( + "Exception during startup:~n~s", + [lager:pr_stacktrace(Stacktrace, {Class, Exception})]). + +log_message(Message) -> + Lines = string:split( + ?BOOT_FAILED_HEADER ++ + Message ++ + ?BOOT_FAILED_FOOTER, + [$\n], + all), + [rabbit_log_prelaunch:error("~s", [Line]) || Line <- Lines], + [io:format(standard_error, "~s~n", [Line]) || Line <- Lines], + timer:sleep(1000), + ok. diff --git a/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sup.erl b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sup.erl new file mode 100644 index 0000000000..ec51989fb9 --- /dev/null +++ b/apps/rabbitmq_prelaunch/src/rabbit_prelaunch_sup.erl @@ -0,0 +1,17 @@ +-module(rabbit_prelaunch_sup). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + %% `rabbit_prelaunch` does not start a process, it only configures + %% the node. + Prelaunch = #{id => prelaunch, + start => {rabbit_prelaunch, run_prelaunch_first_phase, []}, + restart => transient}, + Procs = [Prelaunch], + {ok, {{one_for_one, 1, 5}, Procs}}. diff --git a/scripts/cuttlefish b/scripts/cuttlefish Binary files differdeleted file mode 100755 index e63ac1c1b3..0000000000 --- a/scripts/cuttlefish +++ /dev/null diff --git a/scripts/rabbitmq-defaults b/scripts/rabbitmq-defaults index ba09c7ce62..eca44d8af4 100755 --- a/scripts/rabbitmq-defaults +++ b/scripts/rabbitmq-defaults @@ -18,41 +18,10 @@ ### next line potentially updated in package install steps SYS_PREFIX= -### next line will be updated when generating a standalone release -ERL_DIR= - CLEAN_BOOT_FILE=start_clean SASL_BOOT_FILE=start_sasl - -if [ -f "${RABBITMQ_HOME}/erlang.mk" ]; then - # RabbitMQ is executed from its source directory. The plugins - # directory and ERL_LIBS are tuned based on this. - RABBITMQ_DEV_ENV=1 -fi - -## Set default values - BOOT_MODULE="rabbit" -CONFIG_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq -LOG_BASE=${SYS_PREFIX}/var/log/rabbitmq -MNESIA_BASE=${SYS_PREFIX}/var/lib/rabbitmq/mnesia -ENABLED_PLUGINS_FILE=${SYS_PREFIX}/etc/rabbitmq/enabled_plugins -GENERATED_CONFIG_DIR=${SYS_PREFIX}/var/lib/rabbitmq/config -ADVANCED_CONFIG_FILE=${SYS_PREFIX}/etc/rabbitmq/advanced.config -SCHEMA_DIR=${SYS_PREFIX}/var/lib/rabbitmq/schema - -PLUGINS_DIR="${RABBITMQ_HOME}/plugins" - -# RABBIT_HOME can contain a version number, so default plugins -# directory can be hard to find if we want to package some plugin -# separately. When RABBITMQ_HOME points to a standard location where -# it's usually being installed by package managers, we add -# "/usr/lib/rabbitmq/plugins" to plugin search path. -case "$RABBITMQ_HOME" in - /usr/lib/rabbitmq/*) - PLUGINS_DIR="/usr/lib/rabbitmq/plugins:$PLUGINS_DIR" - ;; -esac - -CONF_ENV_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq-env.conf +if test -z "$CONF_ENV_FILE" && test -z "$RABBITMQ_CONF_ENV_FILE"; then + CONF_ENV_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq-env.conf +fi diff --git a/scripts/rabbitmq-defaults.bat b/scripts/rabbitmq-defaults.bat index 18d4f46943..0da11f2a0c 100644 --- a/scripts/rabbitmq-defaults.bat +++ b/scripts/rabbitmq-defaults.bat @@ -1,23 +1,8 @@ @echo off
-REM ### next line potentially updated in package install steps
-REM set SYS_PREFIX=
-
-REM ### next line will be updated when generating a standalone release
-REM ERL_DIR=
-set ERL_DIR=
-
-REM This boot files isn't referenced in the batch scripts
-REM set SASL_BOOT_FILE=start_sasl
+set SASL_BOOT_FILE=start_sasl
set CLEAN_BOOT_FILE=start_clean
-
-if exist "%RABBITMQ_HOME%\erlang.mk" (
- REM RabbitMQ is executed from its source directory. The plugins
- REM directory and ERL_LIBS are tuned based on this.
- set RABBITMQ_DEV_ENV=1
-)
-
-REM ## Set default values
+set BOOT_MODULE=rabbit
if "!RABBITMQ_BASE!"=="" (
set RABBITMQ_BASE=!APPDATA!\RabbitMQ
@@ -29,22 +14,4 @@ if not exist "!RABBITMQ_BASE!" ( mkdir "!RABBITMQ_BASE!"
)
-REM BOOT_MODULE="rabbit"
-REM CONFIG_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq
-REM LOG_BASE=${SYS_PREFIX}/var/log/rabbitmq
-REM MNESIA_BASE=${SYS_PREFIX}/var/lib/rabbitmq/mnesia
-REM ENABLED_PLUGINS_FILE=${SYS_PREFIX}/etc/rabbitmq/enabled_plugins
-set BOOT_MODULE=rabbit
-set CONFIG_FILE=!RABBITMQ_BASE!\rabbitmq
-set LOG_BASE=!RABBITMQ_BASE!\log
-set MNESIA_BASE=!RABBITMQ_BASE!\db
-set ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins
-set GENERATED_CONFIG_DIR=!RABBITMQ_BASE!\config
-set ADVANCED_CONFIG_FILE=!RABBITMQ_BASE!\advanced.config
-set SCHEMA_DIR=!RABBITMQ_BASE!\schema
-
-REM PLUGINS_DIR="${RABBITMQ_HOME}/plugins"
-for /f "delims=" %%F in ("!TDP0!..\plugins") do set PLUGINS_DIR=%%~dpF%%~nF%%~xF
-
-REM CONF_ENV_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq-env.conf
set CONF_ENV_FILE=!RABBITMQ_BASE!\rabbitmq-env-conf.bat
diff --git a/scripts/rabbitmq-diagnostics.bat b/scripts/rabbitmq-diagnostics.bat index 77078389b0..3a94c7520f 100644 --- a/scripts/rabbitmq-diagnostics.bat +++ b/scripts/rabbitmq-diagnostics.bat @@ -49,10 +49,6 @@ if not defined ERL_CRASH_DUMP_SECONDS ( -boot !CLEAN_BOOT_FILE! ^
-noinput -noshell -hidden -smp enable ^
!RABBITMQ_CTL_ERL_ARGS! ^
--kernel inet_dist_listen_min !RABBITMQ_CTL_DIST_PORT_MIN! ^
--kernel inet_dist_listen_max !RABBITMQ_CTL_DIST_PORT_MAX! ^
--sasl errlog_type error ^
--mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^
-run escript start ^
-escript main rabbitmqctl_escript ^
-extra "%RABBITMQ_HOME%\escript\rabbitmq-diagnostics" !STAR!
@@ -61,4 +57,6 @@ if ERRORLEVEL 1 ( exit /B %ERRORLEVEL%
)
+EXIT /B 0
+
endlocal
diff --git a/scripts/rabbitmq-env b/scripts/rabbitmq-env index 2430e76b5d..26c1db9026 100755 --- a/scripts/rabbitmq-env +++ b/scripts/rabbitmq-env @@ -91,20 +91,6 @@ rmq_realpath() { fi } -path_contains_existing_directory() { - local path="${1:?}" - local dir - local rc - local IFS=" - " - for dir in $(echo "$path" | tr ':' '\n'); do - if [ -d "$dir" ]; then - return 0 - fi - done - return 1 -} - RABBITMQ_HOME="$(rmq_realpath "${RABBITMQ_SCRIPTS_DIR}/..")" ESCRIPT_DIR="${RABBITMQ_HOME}/escript" @@ -118,7 +104,10 @@ saved_RABBITMQ_PID_FILE="$RABBITMQ_PID_FILE" ## Get configuration variables from the configure environment file [ "x" = "x$RABBITMQ_CONF_ENV_FILE" ] && RABBITMQ_CONF_ENV_FILE=${CONF_ENV_FILE} -[ -f ${RABBITMQ_CONF_ENV_FILE} ] && . ${RABBITMQ_CONF_ENV_FILE} || true +if [ -f "${RABBITMQ_CONF_ENV_FILE}" ]; then + CONF_ENV_FILE_PHASE=rabbitmq-env + . ${RABBITMQ_CONF_ENV_FILE} || true +fi [ -n "$ERL_EPMD_PORT" ] && export ERL_EPMD_PORT [ -n "$ERL_EPMD_ADDRESS" ] && export ERL_EPMD_ADDRESS @@ -142,125 +131,17 @@ DEFAULT_MAX_NUMBER_OF_ATOMS=5000000 ## Common server defaults SERVER_ERL_ARGS=" +P $RABBITMQ_MAX_NUMBER_OF_PROCESSES +t $RABBITMQ_MAX_NUMBER_OF_ATOMS +stbt $RABBITMQ_SCHEDULER_BIND_TYPE +zdbbl $RABBITMQ_DISTRIBUTION_BUFFER_SIZE " -[ "x" = "x$RABBITMQ_USE_LONGNAME" ] && RABBITMQ_USE_LONGNAME=${USE_LONGNAME} -if [ "xtrue" = "x$RABBITMQ_USE_LONGNAME" ] ; then - RABBITMQ_NAME_TYPE=-name - [ "x" = "x$HOSTNAME" ] && HOSTNAME=`env hostname -f` - [ "x" = "x$NODENAME" ] && NODENAME=rabbit@${HOSTNAME} -else - RABBITMQ_NAME_TYPE=-sname - [ "x" = "x$HOSTNAME" ] && HOSTNAME=`env hostname` - [ "x" = "x$NODENAME" ] && NODENAME=rabbit@${HOSTNAME%%.*} -fi - ##--- Set environment vars RABBITMQ_<var_name> to defaults if not set -rmq_normalize_path() { - local path=$1 - - # Remove redundant slashes and strip a trailing slash for a - # PATH-like vars - ':' is the delimiter - echo "$path" | sed -e 's#/\{2,\}#/#g' -e 's#/$##' -e 's#/:#:#g' -} - -rmq_normalize_path_var() { - local var warning - - local prefix="WARNING:" - - for var in "$@"; do - local path=$(eval "echo \"\$$var\"") - case "$path" in - */) - warning=1 - echo "$prefix Removing trailing slash from $var" 1>&2 - ;; - esac - - eval "$var=$(rmq_normalize_path "$path")" - - if [ "x$warning" = "x1" ]; then - prefix=" " - fi - done -} - -rmq_check_if_shared_with_mnesia() { - local var warning - - local mnesia_dir=$(rmq_realpath "${RABBITMQ_MNESIA_DIR}") - local prefix="WARNING:" - - for var in "$@"; do - local dir=$(eval "echo \"\$$var\"") - - case $(rmq_realpath "$dir") in - ${mnesia_dir}) - warning=1 - echo "$prefix $var is equal to RABBITMQ_MNESIA_DIR" 1>&2 - ;; - ${mnesia_dir}/*) - warning=1 - echo "$prefix $var is located inside RABBITMQ_MNESIA_DIR" 1>&2 - ;; - esac - - if [ "x$warning" = "x1" ]; then - prefix=" " - fi - done - - if [ "x$warning" = "x1" ]; then - echo "$prefix => Auto-clustering will not work ('cluster_nodes' in rabbitmq.config)" 1>&2 - fi -} - -DEFAULT_NODE_IP_ADDRESS=auto -DEFAULT_NODE_PORT=5672 - -[ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] && RABBITMQ_NODE_IP_ADDRESS=${NODE_IP_ADDRESS} -[ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_PORT=${NODE_PORT} - -[ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] && [ "x" != "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_IP_ADDRESS=${DEFAULT_NODE_IP_ADDRESS} -[ "x" != "x$RABBITMQ_NODE_IP_ADDRESS" ] && [ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_PORT=${DEFAULT_NODE_PORT} - -[ "x" = "x$RABBITMQ_DIST_PORT" ] && RABBITMQ_DIST_PORT=${DIST_PORT} -[ "x" = "x$RABBITMQ_DIST_PORT" ] && [ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_DIST_PORT=$((${DEFAULT_NODE_PORT} + 20000)) -[ "x" = "x$RABBITMQ_DIST_PORT" ] && [ "x" != "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_DIST_PORT=$((${RABBITMQ_NODE_PORT} + 20000)) - -[ "x" = "x$RABBITMQ_CTL_ERL_ARGS" ] && RABBITMQ_CTL_ERL_ARGS=${CTL_ERL_ARGS} -[ "x" = "x$RABBITMQ_CTL_DIST_PORT_MIN" ] && RABBITMQ_CTL_DIST_PORT_MIN=${CTL_DIST_PORT_MIN} -[ "x" = "x$RABBITMQ_CTL_DIST_PORT_MAX" ] && RABBITMQ_CTL_DIST_PORT_MAX=${CTL_DIST_PORT_MAX} -[ "x" = "x$RABBITMQ_CTL_DIST_PORT_MIN" ] && RABBITMQ_CTL_DIST_PORT_MIN=$((${RABBITMQ_DIST_PORT} + 10000)) -[ "x" = "x$RABBITMQ_CTL_DIST_PORT_MAX" ] && RABBITMQ_CTL_DIST_PORT_MAX=$((${RABBITMQ_DIST_PORT} + 10010)) - -[ "x" = "x$RABBITMQ_NODENAME" ] && RABBITMQ_NODENAME=${NODENAME} +# FIXME [ "x" = "x$RABBITMQ_IO_THREAD_POOL_SIZE" ] && RABBITMQ_IO_THREAD_POOL_SIZE=${IO_THREAD_POOL_SIZE} [ "x" = "x$RABBITMQ_SERVER_ERL_ARGS" ] && RABBITMQ_SERVER_ERL_ARGS=${SERVER_ERL_ARGS} -[ "x" = "x$RABBITMQ_CONFIG_FILE" ] && RABBITMQ_CONFIG_FILE=${CONFIG_FILE} -[ "x" = "x$RABBITMQ_LOG_BASE" ] && RABBITMQ_LOG_BASE=${LOG_BASE} -[ "x" = "x$RABBITMQ_MNESIA_BASE" ] && RABBITMQ_MNESIA_BASE=${MNESIA_BASE} [ "x" = "x$RABBITMQ_SERVER_START_ARGS" ] && RABBITMQ_SERVER_START_ARGS=${SERVER_START_ARGS} [ "x" = "x$RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS" ] && RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS=${SERVER_ADDITIONAL_ERL_ARGS} [ "x" = "x$RABBITMQ_SERVER_CODE_PATH" ] && RABBITMQ_SERVER_CODE_PATH=${SERVER_CODE_PATH} -[ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${MNESIA_DIR} -[ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME} -[ "x" = "x$RABBITMQ_QUORUM_DIR" ] && RABBITMQ_QUORUM_DIR=${RABBITMQ_MNESIA_DIR}/quorum -[ "x" = "x$RABBITMQ_GENERATED_CONFIG_DIR" ] && RABBITMQ_GENERATED_CONFIG_DIR=${GENERATED_CONFIG_DIR} -[ "x" = "x$RABBITMQ_ADVANCED_CONFIG_FILE" ] && RABBITMQ_ADVANCED_CONFIG_FILE=${ADVANCED_CONFIG_FILE} -[ "x" = "x$RABBITMQ_SCHEMA_DIR" ] && RABBITMQ_SCHEMA_DIR=${SCHEMA_DIR} [ "x" = "x$RABBITMQ_IGNORE_SIGINT" ] && RABBITMQ_IGNORE_SIGINT="true" [ "xtrue" = "x$RABBITMQ_IGNORE_SIGINT" ] && RABBITMQ_IGNORE_SIGINT_FLAG="+B i" -rmq_normalize_path_var \ - RABBITMQ_CONFIG_FILE \ - RABBITMQ_LOG_BASE \ - RABBITMQ_MNESIA_BASE \ - RABBITMQ_MNESIA_DIR \ - RABBITMQ_QUORUM_DIR - -[ "x" = "x$RABBITMQ_PID_FILE" ] && RABBITMQ_PID_FILE="$PID_FILE" - if [ -n "$saved_RABBITMQ_PID_FILE" ] && \ [ "$saved_RABBITMQ_PID_FILE" != "$RABBITMQ_PID_FILE" ] then @@ -271,155 +152,19 @@ then RABBITMQ_PID_FILE="$saved_RABBITMQ_PID_FILE" fi -# Note: at this point, no RABBITMQ_PID_FILE is set so we use the mnesia dir value -[ "x" = "x$RABBITMQ_PID_FILE" ] && RABBITMQ_PID_FILE="${RABBITMQ_MNESIA_DIR}.pid" - -rmq_normalize_path_var RABBITMQ_PID_FILE - [ "x" = "x$RABBITMQ_BOOT_MODULE" ] && RABBITMQ_BOOT_MODULE=${BOOT_MODULE} -[ "x" != "x$RABBITMQ_FEATURE_FLAGS_FILE" ] && RABBITMQ_FEATURE_FLAGS_FILE_source=environment -[ "x" = "x$RABBITMQ_FEATURE_FLAGS_FILE" ] && RABBITMQ_FEATURE_FLAGS_FILE=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-feature_flags -rmq_normalize_path_var RABBITMQ_FEATURE_FLAGS_FILE - -[ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${PLUGINS_EXPAND_DIR} -[ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-plugins-expand -rmq_normalize_path_var RABBITMQ_PLUGINS_EXPAND_DIR - -[ "x" != "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE_source=environment -[ "x" = "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE=${ENABLED_PLUGINS_FILE} -rmq_normalize_path_var RABBITMQ_ENABLED_PLUGINS_FILE - -[ "x" != "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR_source=environment -[ "x" = "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR=${PLUGINS_DIR} -rmq_normalize_path_var RABBITMQ_PLUGINS_DIR - -## Log rotation -[ "x" = "x$RABBITMQ_LOGS" ] && RABBITMQ_LOGS=${LOGS} -[ "x" != "x$RABBITMQ_LOGS" ] && export RABBITMQ_LOGS_source=environment -[ "x" = "x$RABBITMQ_LOGS" ] && RABBITMQ_LOGS="${RABBITMQ_LOG_BASE}/${RABBITMQ_NODENAME}.log" -[ "x" = "x$RABBITMQ_UPGRADE_LOG" ] && RABBITMQ_UPGRADE_LOG="${RABBITMQ_LOG_BASE}/${RABBITMQ_NODENAME}_upgrade.log" -[ "x" = "x$ERL_CRASH_DUMP" ] && ERL_CRASH_DUMP="${RABBITMQ_LOG_BASE}/erl_crash.dump" - -rmq_normalize_path_var RABBITMQ_LOGS - -rmq_normalize_path_var RABBITMQ_UPGRADE_LOG - -# Check if files and directories non-related to Mnesia are configured -# to be in $RABBITMQ_MNESIA_DIR. If this is the case, issue a warning -# because it will prevent auto-clustering from working (the node will be -# considered non-virgin). - -rmq_check_if_shared_with_mnesia \ - RABBITMQ_CONFIG_FILE \ - RABBITMQ_LOG_BASE \ - RABBITMQ_PID_FILE \ - RABBITMQ_FEATURE_FLAGS_FILE \ - RABBITMQ_PLUGINS_EXPAND_DIR \ - RABBITMQ_ENABLED_PLUGINS_FILE \ - RABBITMQ_PLUGINS_DIR \ - RABBITMQ_LOGS \ - RABBITMQ_UPGRADE_LOG - ##--- End of overridden <var_name> variables -## Development-specific environment. -if [ "${RABBITMQ_DEV_ENV}" ]; then - if [ "$RABBITMQ_FEATURE_FLAGS_FILE_source" != 'environment' -o \ - "$RABBITMQ_PLUGINS_DIR_source" != 'environment' -o \ - "$RABBITMQ_ENABLED_PLUGINS_FILE_source" != 'environment' ]; then - # We need to query the running node for the plugins directory - # and the "enabled plugins" file. - for arg in "$@"; do - case "$arg" in - -n) - next_is_node=1 - ;; - *) - if test "$next_is_node"; then - # If the executed script is being passed a remote node - # name, use it here to query the remote node. - node_arg="-n $arg" - break - fi - ;; - esac - done - eval $( (${RABBITMQ_SCRIPTS_DIR}/rabbitmqctl $node_arg eval \ - '{ok, F} = application:get_env(rabbit, feature_flags_file), - {ok, P} = application:get_env(rabbit, plugins_dir), - {ok, E} = application:get_env(rabbit, enabled_plugins_file), - B = os:getenv("RABBITMQ_MNESIA_BASE"), - M = os:getenv("RABBITMQ_MNESIA_DIR"), - io:format( - "feature_flags_file=\"~s\"~n" - "plugins_dir=\"~s\"~n" - "enabled_plugins_file=\"~s\"~n" - "mnesia_base=\"~s\"~n" - "mnesia_dir=\"~s\"~n", [F, P, E, B, M]).' \ - 2>/dev/null | grep -E '^(feature_flags_file|plugins_dir|enabled_plugins_file|mnesia_base|mnesia_dir)=') || :) - - if [ "${feature_flags_file}" -a \ - "$RABBITMQ_FEATURE_FLAGS_FILE_source" != 'environment' ]; then - RABBITMQ_FEATURE_FLAGS_FILE="${feature_flags_file}" - fi - if [ "${plugins_dir}" -a \ - "$RABBITMQ_PLUGINS_DIR_source" != 'environment' ]; then - RABBITMQ_PLUGINS_DIR="${plugins_dir}" - fi - if [ "${enabled_plugins_file}" -a \ - "$RABBITMQ_ENABLED_PLUGINS_FILE_source" != 'environment' ]; then - RABBITMQ_ENABLED_PLUGINS_FILE="${enabled_plugins_file}" - fi - if [ "${mnesia_base}" -a \ - "$RABBITMQ_MNESIA_BASE_source" != 'environment' ]; then - RABBITMQ_MNESIA_BASE="${mnesia_base}" - fi - if [ "${mnesia_dir}" -a \ - "$RABBITMQ_MNESIA_DIR_source" != 'environment' ]; then - RABBITMQ_MNESIA_DIR="${mnesia_dir}" - fi - if [ "${mnesia_dir}" -a \ - "$RABBITMQ_QUORUM_DIR_source" != 'environment' ]; then - RABBITMQ_QUORUM_DIR="${mnesia_dir}/quorum" - fi - fi - - if path_contains_existing_directory "${RABBITMQ_PLUGINS_DIR}" ; then - # RabbitMQ was started with "make run-broker" from its own - # source tree. Take rabbit_common from the plugins directory. - ERL_LIBS="${RABBITMQ_PLUGINS_DIR}:${ERL_LIBS}" +_rmq_env_set_erl_libs() +{ + if [ -n "$ERL_LIBS" ] + then + export ERL_LIBS="$RABBITMQ_HOME/plugins:$ERL_LIBS" else - # RabbitMQ runs from a testsuite or a plugin. The .ez files are - # not available under RabbitMQ source tree. We need to look at - # $DEPS_DIR and default locations. - - if [ "${DEPS_DIR}" -a -d "${DEPS_DIR}/rabbit_common/ebin" ]; then - # $DEPS_DIR is set, and it contains rabbitmq-common, use - # this. - DEPS_DIR_norm="${DEPS_DIR}" - elif [ -f "${RABBITMQ_SCRIPTS_DIR}/../../../erlang.mk" -a \ - -d "${RABBITMQ_SCRIPTS_DIR}/../../rabbit_common/ebin" ]; then - # Look at default locations: "deps" subdirectory inside a - # plugin or the Umbrella. - DEPS_DIR_norm="${RABBITMQ_SCRIPTS_DIR}/../.." - fi - DEPS_DIR_norm=$(rmq_realpath "${DEPS_DIR_norm}") - - ERL_LIBS="${DEPS_DIR_norm}:${ERL_LIBS}" + export ERL_LIBS="$RABBITMQ_HOME/plugins" fi -else - if path_contains_existing_directory "${RABBITMQ_PLUGINS_DIR}" ; then - # RabbitMQ was started from its install directory. Take - # rabbit_common from the plugins directory. - ERL_LIBS="${RABBITMQ_PLUGINS_DIR}:${ERL_LIBS}" - fi -fi - -ERL_LIBS=${ERL_LIBS%:} -if [ "$ERL_LIBS" ]; then - export ERL_LIBS -fi +} run_escript() { @@ -428,17 +173,15 @@ run_escript() escript="${1:?escript must be defined}" shift + _rmq_env_set_erl_libs + # Important: do not quote RABBITMQ_CTL_ERL_ARGS as they must be # word-split # shellcheck disable=SC2086 - exec "${ERL_DIR}erl" +B \ + exec erl +B \ -boot "$CLEAN_BOOT_FILE" \ -noinput -noshell -hidden -smp enable \ $RABBITMQ_CTL_ERL_ARGS \ - -kernel inet_dist_listen_min "$RABBITMQ_CTL_DIST_PORT_MIN" \ - -kernel inet_dist_listen_max "$RABBITMQ_CTL_DIST_PORT_MAX" \ - -sasl errlog_type error \ - -mnesia dir "\"$RABBITMQ_MNESIA_DIR\"" \ -run escript start \ -escript main "$escript_main" \ -extra "$escript" "$@" diff --git a/scripts/rabbitmq-env.bat b/scripts/rabbitmq-env.bat index e178deb48c..92853a2362 100644 --- a/scripts/rabbitmq-env.bat +++ b/scripts/rabbitmq-env.bat @@ -14,6 +14,12 @@ set SCRIPT_DIR=%TDP0% set SCRIPT_NAME=%1
for /f "delims=" %%F in ("%SCRIPT_DIR%..") do set RABBITMQ_HOME=%%~dpF%%~nF%%~xF
+if defined ERL_LIBS (
+ set ERL_LIBS=%RABBITMQ_HOME%\plugins;%ERL_LIBS%
+) else (
+ set ERL_LIBS=%RABBITMQ_HOME%\plugins
+)
+
REM If ERLANG_HOME is not defined, check if "erl.exe" is available in
REM the path and use that.
if not defined ERLANG_HOME (
@@ -82,163 +88,16 @@ if "!RABBITMQ_MAX_NUMBER_OF_ATOMS!"=="" ( set RABBITMQ_MAX_NUMBER_OF_ATOMS=!DEFAULT_MAX_NUMBER_OF_ATOMS!
)
-REM Common defaults
+REM Common server defaults
set SERVER_ERL_ARGS=+P !RABBITMQ_MAX_NUMBER_OF_PROCESSES! +t !RABBITMQ_MAX_NUMBER_OF_ATOMS! +stbt !RABBITMQ_SCHEDULER_BIND_TYPE! +zdbbl !RABBITMQ_DISTRIBUTION_BUFFER_SIZE!
-REM Check for the short names here too
-if "!RABBITMQ_USE_LONGNAME!"=="true" (
- set RABBITMQ_NAME_TYPE=-name
- set NAMETYPE=longnames
-) else (
- if "!USE_LONGNAME!"=="true" (
- set RABBITMQ_USE_LONGNAME=true
- set RABBITMQ_NAME_TYPE=-name
- set NAMETYPE=longnames
- ) else (
- set RABBITMQ_USE_LONGNAME=false
- set RABBITMQ_NAME_TYPE=-sname
- set NAMETYPE=shortnames
- )
-)
-
-REM [ "x" = "x$RABBITMQ_NODENAME" ] && RABBITMQ_NODENAME=${NODENAME}
-if "!RABBITMQ_NODENAME!"=="" (
- if "!NODENAME!"=="" (
- REM We use Erlang to query the local hostname because
- REM !COMPUTERNAME! and Erlang may return different results.
- REM Start erl with -sname to make sure epmd is started.
- call "%ERLANG_HOME%\bin\erl.exe" -A0 -noinput -boot start_clean -sname rabbit-prelaunch-epmd -eval "init:stop()." >nul 2>&1
- for /f "delims=" %%F in ('call "%ERLANG_HOME%\bin\erl.exe" -A0 -noinput -boot start_clean -eval "net_kernel:start([list_to_atom(""rabbit-gethostname-"" ++ os:getpid()), %NAMETYPE%]), [_, H] = string:tokens(atom_to_list(node()), ""@""), io:format(""~s~n"", [H]), init:stop()."') do @set HOSTNAME=%%F
- set RABBITMQ_NODENAME=rabbit@!HOSTNAME!
- set HOSTNAME=
- ) else (
- set RABBITMQ_NODENAME=!NODENAME!
- )
-)
-set NAMETYPE=
-
-REM
REM ##--- Set environment vars RABBITMQ_<var_name> to defaults if not set
-REM
-REM DEFAULT_NODE_IP_ADDRESS=auto
-REM DEFAULT_NODE_PORT=5672
-REM [ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] && RABBITMQ_NODE_IP_ADDRESS=${NODE_IP_ADDRESS}
-REM [ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_PORT=${NODE_PORT}
-REM [ "x" = "x$RABBITMQ_NODE_IP_ADDRESS" ] && [ "x" != "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_IP_ADDRESS=${DEFAULT_NODE_IP_ADDRESS}
-REM [ "x" != "x$RABBITMQ_NODE_IP_ADDRESS" ] && [ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_NODE_PORT=${DEFAULT_NODE_PORT}
-
-if "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
- if not "!NODE_IP_ADDRESS!"=="" (
- set RABBITMQ_NODE_IP_ADDRESS=!NODE_IP_ADDRESS!
- )
-)
-
-if "!RABBITMQ_NODE_PORT!"=="" (
- if not "!NODE_PORT!"=="" (
- set RABBITMQ_NODE_PORT=!NODE_PORT!
- )
-)
-
-if "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
- if not "!RABBITMQ_NODE_PORT!"=="" (
- set RABBITMQ_NODE_IP_ADDRESS=auto
- )
-) else (
- if "!RABBITMQ_NODE_PORT!"=="" (
- set RABBITMQ_NODE_PORT=5672
- )
-)
-
-REM [ "x" = "x$RABBITMQ_DIST_PORT" ] && RABBITMQ_DIST_PORT=${DIST_PORT}
-REM [ "x" = "x$RABBITMQ_DIST_PORT" ] && [ "x" = "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_DIST_PORT=$((${DEFAULT_NODE_PORT} + 20000))
-REM [ "x" = "x$RABBITMQ_DIST_PORT" ] && [ "x" != "x$RABBITMQ_NODE_PORT" ] && RABBITMQ_DIST_PORT=$((${RABBITMQ_NODE_PORT} + 20000))
-
-if "!RABBITMQ_DIST_PORT!"=="" (
- if "!DIST_PORT!"=="" (
- if "!RABBITMQ_NODE_PORT!"=="" (
- set RABBITMQ_DIST_PORT=25672
- ) else (
- set /a RABBITMQ_DIST_PORT=20000+!RABBITMQ_NODE_PORT!
- )
- ) else (
- set RABBITMQ_DIST_PORT=!DIST_PORT!
- )
-)
REM [ "x" = "x$RABBITMQ_SERVER_ERL_ARGS" ] && RABBITMQ_SERVER_ERL_ARGS=${SERVER_ERL_ARGS}
if "!RABBITMQ_SERVER_ERL_ARGS!"=="" (
set RABBITMQ_SERVER_ERL_ARGS=!SERVER_ERL_ARGS!
)
-REM [ "x" = "x$RABBITMQ_CONFIG_FILE" ] && RABBITMQ_CONFIG_FILE=${CONFIG_FILE}
-if "!RABBITMQ_CONFIG_FILE!"=="" (
- if "!CONFIG_FILE!"=="" (
- set RABBITMQ_CONFIG_FILE=!RABBITMQ_BASE!\rabbitmq
- ) else (
- set RABBITMQ_CONFIG_FILE=!CONFIG_FILE:"=!
- )
-) else (
- set RABBITMQ_CONFIG_FILE=!RABBITMQ_CONFIG_FILE:"=!
-)
-
-if "!RABBITMQ_GENERATED_CONFIG_DIR!"=="" (
- if "!GENERATED_CONFIG_DIR!"=="" (
- set RABBITMQ_GENERATED_CONFIG_DIR=!RABBITMQ_BASE!\config
- ) else (
- set RABBITMQ_GENERATED_CONFIG_DIR=!GENERATED_CONFIG_DIR:"=!
- )
-) else (
- set RABBITMQ_GENERATED_CONFIG_DIR=!RABBITMQ_GENERATED_CONFIG_DIR:"=!
-)
-
-if "!RABBITMQ_ADVANCED_CONFIG_FILE!"=="" (
- if "!ADVANCED_CONFIG_FILE!"=="" (
- set RABBITMQ_ADVANCED_CONFIG_FILE=!RABBITMQ_BASE!\advanced.config
- ) else (
- set RABBITMQ_ADVANCED_CONFIG_FILE=!ADVANCED_CONFIG_FILE:"=!
- )
-) else (
- set RABBITMQ_ADVANCED_CONFIG_FILE=!RABBITMQ_ADVANCED_CONFIG_FILE:"=!
-)
-
-if "!RABBITMQ_SCHEMA_DIR!" == "" (
- if "!SCHEMA_DIR!"=="" (
- set RABBITMQ_SCHEMA_DIR=!RABBITMQ_HOME!\priv\schema
- ) else (
- set RABBITMQ_SCHEMA_DIR=!SCHEMA_DIR:"=!
- )
-) else (
- set RABBITMQ_SCHEMA_DIR=!RABBITMQ_SCHEMA_DIR:"=!
-)
-
-REM [ "x" = "x$RABBITMQ_LOG_BASE" ] && RABBITMQ_LOG_BASE=${LOG_BASE}
-if "!RABBITMQ_LOG_BASE!"=="" (
- if "!LOG_BASE!"=="" (
- set RABBITMQ_LOG_BASE=!RABBITMQ_BASE!\log
- ) else (
- set RABBITMQ_LOG_BASE=!LOG_BASE:"=!
- )
-) else (
- set RABBITMQ_LOG_BASE=!RABBITMQ_LOG_BASE:"=!
-)
-if not exist "!RABBITMQ_LOG_BASE!" (
- mkdir "!RABBITMQ_LOG_BASE!"
-)
-
-REM [ "x" = "x$RABBITMQ_MNESIA_BASE" ] && RABBITMQ_MNESIA_BASE=${MNESIA_BASE}
-if "!RABBITMQ_MNESIA_BASE!"=="" (
- if "!MNESIA_BASE!"=="" (
- set RABBITMQ_MNESIA_BASE=!RABBITMQ_BASE!\db
- ) else (
- set RABBITMQ_MNESIA_BASE=!MNESIA_BASE:"=!
- )
-) else (
- set RABBITMQ_MNESIA_BASE=!RABBITMQ_MNESIA_BASE:"=!
-)
-if not exist "!RABBITMQ_MNESIA_BASE!" (
- mkdir "!RABBITMQ_MNESIA_BASE!"
-)
-
REM [ "x" = "x$RABBITMQ_SERVER_START_ARGS" ] && RABBITMQ_SERVER_START_ARGS=${SERVER_START_ARGS}
if "!RABBITMQ_SERVER_START_ARGS!"=="" (
if not "!SERVER_START_ARGS!"=="" (
@@ -253,34 +112,6 @@ if "!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS!"=="" ( )
)
-REM [ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${MNESIA_DIR}
-REM [ "x" = "x$RABBITMQ_MNESIA_DIR" ] && RABBITMQ_MNESIA_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}
-if "!RABBITMQ_MNESIA_DIR!"=="" (
- if "!MNESIA_DIR!"=="" (
- set RABBITMQ_MNESIA_DIR=!RABBITMQ_MNESIA_BASE!\!RABBITMQ_NODENAME!-mnesia
- ) else (
- set RABBITMQ_MNESIA_DIR=!MNESIA_DIR:"=!
- )
-) else (
- set RABBITMQ_MNESIA_DIR=!RABBITMQ_MNESIA_DIR:"=!
-)
-if not exist "!RABBITMQ_MNESIA_DIR!" (
- mkdir "!RABBITMQ_MNESIA_DIR!"
-)
-
-REM [ "x" = "x$RABBITMQ_QUORUM_DIR" ] && RABBITMQ_QUORUM_DIR=${RABBITMQ_MNESIA_DIR}/quorum
-if "!RABBITMQ_QUORUM_DIR!"=="" (
- set RABBITMQ_QUORUM_DIR=!RABBITMQ_MNESIA_DIR!\quorum
-)
-if not exist "!RABBITMQ_QUORUM_DIR!" (
- mkdir "!RABBITMQ_QUORUM_DIR!"
-)
-for /f "delims=" %%F in ("!RABBITMQ_QUORUM_DIR!") do set RABBITMQ_QUORUM_DIR=%%~sF
-
-REM [ "x" = "x$RABBITMQ_PID_FILE" ] && RABBITMQ_PID_FILE=${PID_FILE}
-REM [ "x" = "x$RABBITMQ_PID_FILE" ] && RABBITMQ_PID_FILE=${RABBITMQ_MNESIA_DIR}.pid
-REM No Windows equivalent
-
REM [ "x" = "x$RABBITMQ_BOOT_MODULE" ] && RABBITMQ_BOOT_MODULE=${BOOT_MODULE}
if "!RABBITMQ_BOOT_MODULE!"=="" (
if "!BOOT_MODULE!"=="" (
@@ -290,114 +121,12 @@ if "!RABBITMQ_BOOT_MODULE!"=="" ( )
)
-REM [ "x" = "x$RABBITMQ_FEATURE_FLAGS_FILE" ] && RABBITMQ_FEATURE_FLAGS_FILE=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-feature_flags
-if "!RABBITMQ_FEATURE_FLAGS_FILE!"=="" (
- if "!FEATURE_FLAGS_FILE!"=="" (
- set RABBITMQ_FEATURE_FLAGS_FILE=!RABBITMQ_MNESIA_BASE!\!RABBITMQ_NODENAME!-feature_flags
- ) else (
- set RABBITMQ_FEATURE_FLAGS_FILE=!FEATURE_FLAGS_FILE:"=!
- )
-) else (
- set RABBITMQ_FEATURE_FLAGS_FILE=!RABBITMQ_FEATURE_FLAGS_FILE:"=!
- set RABBITMQ_FEATURE_FLAGS_FILE_source=environment
-)
-
-REM [ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${PLUGINS_EXPAND_DIR}
-REM [ "x" = "x$RABBITMQ_PLUGINS_EXPAND_DIR" ] && RABBITMQ_PLUGINS_EXPAND_DIR=${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-plugins-expand
-if "!RABBITMQ_PLUGINS_EXPAND_DIR!"=="" (
- if "!PLUGINS_EXPAND_DIR!"=="" (
- set RABBITMQ_PLUGINS_EXPAND_DIR=!RABBITMQ_MNESIA_BASE!\!RABBITMQ_NODENAME!-plugins-expand
- ) else (
- set RABBITMQ_PLUGINS_EXPAND_DIR=!PLUGINS_EXPAND_DIR:"=!
- )
-) else (
- set RABBITMQ_PLUGINS_EXPAND_DIR=!RABBITMQ_PLUGINS_EXPAND_DIR:"=!
-)
-
-REM [ "x" = "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE=${ENABLED_PLUGINS_FILE}
-if "!RABBITMQ_ENABLED_PLUGINS_FILE!"=="" (
- if "!ENABLED_PLUGINS_FILE!"=="" (
- set RABBITMQ_ENABLED_PLUGINS_FILE=!RABBITMQ_BASE!\enabled_plugins
- ) else (
- set RABBITMQ_ENABLED_PLUGINS_FILE=!ENABLED_PLUGINS_FILE:"=!
- )
-) else (
- set RABBITMQ_ENABLED_PLUGINS_FILE=!RABBITMQ_ENABLED_PLUGINS_FILE:"=!
- set RABBITMQ_ENABLED_PLUGINS_FILE_source=environment
-)
-if not exist "!RABBITMQ_ENABLED_PLUGINS_FILE!" (
- for /f "delims=" %%F in ("!RABBITMQ_ENABLED_PLUGINS_FILE!") do mkdir "%%~dpF" 2>NUL
- copy /y NUL "!RABBITMQ_ENABLED_PLUGINS_FILE!" >NUL
-)
-
-REM [ "x" = "x$RABBITMQ_PLUGINS_DIR" ] && RABBITMQ_PLUGINS_DIR=${PLUGINS_DIR}
-if "!RABBITMQ_PLUGINS_DIR!"=="" (
- if "!PLUGINS_DIR!"=="" (
- set RABBITMQ_PLUGINS_DIR=!RABBITMQ_HOME!\plugins
- ) else (
- set RABBITMQ_PLUGINS_DIR=!PLUGINS_DIR:"=!
- )
-) else (
- set RABBITMQ_PLUGINS_DIR=!RABBITMQ_PLUGINS_DIR:"=!
- set RABBITMQ_PLUGINS_DIR_source=environment
-)
-if not exist "!RABBITMQ_PLUGINS_DIR!" (
- mkdir "!RABBITMQ_PLUGINS_DIR!"
-)
-
-REM ## Log rotation
-REM [ "x" = "x$RABBITMQ_LOGS" ] && RABBITMQ_LOGS=${LOGS}
-REM [ "x" = "x$RABBITMQ_LOGS" ] && RABBITMQ_LOGS="${RABBITMQ_LOG_BASE}/${RABBITMQ_NODENAME}.log"
-if "!RABBITMQ_LOGS!"=="" (
- if "!LOGS!"=="" (
- set RABBITMQ_LOGS=!RABBITMQ_LOG_BASE!\!RABBITMQ_NODENAME!.log
- ) else (
- set RABBITMQ_LOGS=!LOGS:"=!
- )
-) else (
- set RABBITMQ_LOGS=!RABBITMQ_LOGS:"=!
-)
-if not "!RABBITMQ_LOGS!" == "-" (
- if not exist "!RABBITMQ_LOGS!" (
- for /f "delims=" %%F in ("!RABBITMQ_LOGS!") do mkdir "%%~dpF" 2>NUL
- copy /y NUL "!RABBITMQ_LOGS!" >NUL
- )
-)
-rem [ "x" = "x$RABBITMQ_UPGRADE_LOG" ] && RABBITMQ_UPGRADE_LOG="${RABBITMQ_LOG_BASE}/${RABBITMQ_NODENAME}_upgrade.log"
-if "!RABBITMQ_UPGRADE_LOG!" == "" (
- set RABBITMQ_UPGRADE_LOG=!RABBITMQ_LOG_BASE!\!RABBITMQ_NODENAME!_upgrade.log
-) else (
- set RABBITMQ_UPGRADE_LOG=!RABBITMQ_UPGRADE_LOG:"=!
-)
-REM [ "x" = "x$ERL_CRASH_DUMP"] && ERL_CRASH_DUMP="${RABBITMQ_LOG_BASE}/erl_crash.dump"
-if "!ERL_CRASH_DUMP!"=="" (
- set ERL_CRASH_DUMP=!RABBITMQ_LOG_BASE!\erl_crash.dump
-) else (
- set ERL_CRASH_DUMP=!ERL_CRASH_DUMP:"=!
-)
-
REM [ "x" = "x$RABBITMQ_CTL_ERL_ARGS" ] && RABBITMQ_CTL_ERL_ARGS=${CTL_ERL_ARGS}
if "!RABBITMQ_CTL_ERL_ARGS!"=="" (
if not "!CTL_ERL_ARGS!"=="" (
set RABBITMQ_CTL_ERL_ARGS=!CTL_ERL_ARGS!
)
)
-if "!RABBITMQ_CTL_DIST_PORT_MIN!"=="" (
- if not "!CTL_DIST_PORT_MIN!"=="" (
- set RABBITMQ_CTL_DIST_PORT_MIN=!CTL_DIST_PORT_MIN!
- )
-)
-if "!RABBITMQ_CTL_DIST_PORT_MAX!"=="" (
- if not "!CTL_DIST_PORT_MAX!"=="" (
- set RABBITMQ_CTL_DIST_PORT_MAX=!CTL_DIST_PORT_MAX!
- )
-)
-if "!RABBITMQ_CTL_DIST_PORT_MIN!"=="" (
- set /a RABBITMQ_CTL_DIST_PORT_MIN=10000+!RABBITMQ_DIST_PORT!
-)
-if "!RABBITMQ_CTL_DIST_PORT_MAX!"=="" (
- set /a RABBITMQ_CTL_DIST_PORT_MAX=10010+!RABBITMQ_DIST_PORT!
-)
REM ADDITIONAL WINDOWS ONLY CONFIG ITEMS
@@ -409,93 +138,6 @@ if "!RABBITMQ_SERVICENAME!"=="" ( )
)
-REM Development-specific environment.
-if defined RABBITMQ_DEV_ENV (
- if "!SCRIPT_NAME!" == "rabbitmq-plugins" (
- REM We may need to query the running node for the plugins directory
- REM and the "enabled plugins" file.
- if not "%RABBITMQ_FEATURE_FLAGS_FILE_source%" == "environment" (
- for /f "delims=" %%F in ('!SCRIPT_DIR!\rabbitmqctl.bat eval "{ok, P} = application:get_env(rabbit, feature_flags_file), io:format(""~s~n"", [P])."') do @set feature_flags_file=%%F
- if exist "!feature_flags_file!" (
- set RABBITMQ_FEATURE_FLAGS_FILE=!feature_flags_file:"=!
- )
- REM set feature_flags_file=
- )
- if not "%RABBITMQ_PLUGINS_DIR_source%" == "environment" (
- for /f "delims=" %%F in ('!SCRIPT_DIR!\rabbitmqctl.bat eval "{ok, P} = application:get_env(rabbit, plugins_dir), io:format(""~s~n"", [P])."') do @set plugins_dir=%%F
- if exist "!plugins_dir!" (
- set RABBITMQ_PLUGINS_DIR=!plugins_dir:"=!
- )
- REM set plugins_dir=
- )
- if not "%RABBITMQ_ENABLED_PLUGINS_FILE_source%" == "environment" (
- for /f "delims=" %%F in ('!SCRIPT_DIR!\rabbitmqctl.bat eval "{ok, P} = application:get_env(rabbit, enabled_plugins_file), io:format(""~s~n"", [P])."') do @set enabled_plugins_file=%%F
- if exist "!enabled_plugins_file!" (
- set RABBITMQ_ENABLED_PLUGINS_FILE=!enabled_plugins_file:"=!
- )
- REM set enabled_plugins_file=
- )
- )
-
- if exist "!RABBITMQ_PLUGINS_DIR!" (
- REM RabbitMQ was started with "make run-broker" from its own
- REM source tree. Take rabbit_common from the plugins directory.
- set ERL_LIBS=!RABBITMQ_PLUGINS_DIR!;!ERL_LIBS!
- ) else (
- REM RabbitMQ runs from a testsuite or a plugin. The .ez files are
- REM not available under RabbitMQ source tree. We need to look at
- REM $DEPS_DIR and default locations.
-
- if "!DEPS_DIR!" == "" (
- if exist "!RABBITMQ_HOME!\..\..\deps\rabbit_common\erlang.mk" (
- REM Dependencies in the Umbrella or a plugin.
- set DEPS_DIR_norm=!RABBITMQ_HOME!\..\..\deps
- ) else (
- if exist "!RABBITMQ_HOME!\deps\rabbit_common\erlang.mk" (
- REM Dependencies in the broker.
- set DEPS_DIR_norm=!RABBITMQ_HOME!\deps
- )
- )
- ) else (
- for /f "delims=" %%F in ("!DEPS_DIR!") do @set DEPS_DIR_norm=%%~dpF%%~nF%%~xF
- )
-
- set ERL_LIBS=!DEPS_DIR_norm!;!ERL_LIBS!
- )
-) else (
- if exist "!RABBITMQ_PLUGINS_DIR!" (
- REM RabbitMQ was started from its install directory. Take
- REM rabbit_common from the plugins directory.
- set ERL_LIBS=!RABBITMQ_PLUGINS_DIR:"=!;!ERL_LIBS:"=!
- )
-)
-
-REM Ensure ERL_LIBS begins with valid path
-set ERL_LIBS_orig=%ERL_LIBS:"=%
-set ERL_LIBS=
-call :filter_paths "%ERL_LIBS_orig%"
-goto :filter_paths_done
-
-:filter_paths
-set paths=%1
-set paths=%paths:"=%
-for /f "tokens=1* delims=;" %%a in ("%paths%") do (
- if not "%%a" == "" call :filter_path "%%a"
- if not "%%b" == "" call :filter_paths "%%b"
-)
-set paths=
-goto :eof
-
-:filter_path
-IF "%ERL_LIBS%"=="" (
- set "ERL_LIBS=%~dp1%~n1%~x1"
-) else (
- set "ERL_LIBS=!ERL_LIBS!;%~dp1%~n1%~x1"
-)
-goto :eof
-
-:filter_paths_done
-
REM Environment cleanup
set BOOT_MODULE=
set CONFIG_FILE=
@@ -509,6 +151,6 @@ set SCRIPT_NAME= set TDP0=
REM ##--- End of overridden <var_name> variables
-REM
+
REM # Since we source this elsewhere, don't accidentally stop execution
REM true
diff --git a/scripts/rabbitmq-plugins.bat b/scripts/rabbitmq-plugins.bat index e985151e56..e45e810c53 100644 --- a/scripts/rabbitmq-plugins.bat +++ b/scripts/rabbitmq-plugins.bat @@ -49,10 +49,6 @@ if not defined ERL_CRASH_DUMP_SECONDS ( -boot !CLEAN_BOOT_FILE! ^
-noinput -noshell -hidden -smp enable ^
!RABBITMQ_CTL_ERL_ARGS! ^
--kernel inet_dist_listen_min !RABBITMQ_CTL_DIST_PORT_MIN! ^
--kernel inet_dist_listen_max !RABBITMQ_CTL_DIST_PORT_MAX! ^
--sasl errlog_type error ^
--mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^
-run escript start ^
-escript main rabbitmqctl_escript ^
-extra "%RABBITMQ_HOME%\escript\rabbitmq-plugins" !STAR!
@@ -61,5 +57,7 @@ if ERRORLEVEL 1 ( exit /B %ERRORLEVEL%
)
+EXIT /B 0
+
endlocal
endlocal
diff --git a/scripts/rabbitmq-queues.bat b/scripts/rabbitmq-queues.bat index c90a696806..028e2664c9 100644 --- a/scripts/rabbitmq-queues.bat +++ b/scripts/rabbitmq-queues.bat @@ -49,11 +49,6 @@ if not defined ERL_CRASH_DUMP_SECONDS ( -boot !CLEAN_BOOT_FILE! ^
-noinput -noshell -hidden -smp enable ^
!RABBITMQ_CTL_ERL_ARGS! ^
--kernel inet_dist_listen_min !RABBITMQ_CTL_DIST_PORT_MIN! ^
--kernel inet_dist_listen_max !RABBITMQ_CTL_DIST_PORT_MAX! ^
--sasl errlog_type error ^
--mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^
--nodename !RABBITMQ_NODENAME! ^
-run escript start ^
-escript main rabbitmqctl_escript ^
-extra "%RABBITMQ_HOME%\escript\rabbitmq-queues" !STAR!
@@ -62,5 +57,7 @@ if ERRORLEVEL 1 ( exit /B %ERRORLEVEL%
)
+EXIT /B 0
+
endlocal
endlocal
diff --git a/scripts/rabbitmq-rel b/scripts/rabbitmq-rel new file mode 100755 index 0000000000..a96ec78764 --- /dev/null +++ b/scripts/rabbitmq-rel @@ -0,0 +1,58 @@ +#!/usr/bin/env escript +%% vim:ft=erlang:sw=2:et: + +main(["show-rel"]) -> + Rel = get_rel(), + io:format("~p.~n", [Rel]); +main(["gen-boot"]) -> + generate_rel(), + generate_boot(). + +get_rel() -> + ok = application:load(rabbit), + Apps0 = get_apps(rabbit), + Apps1 = lists:sort( + fun + (_, rabbitmq_prelaunch) -> false; + (rabbitmq_prelaunch, _) -> true; + (_, mnesia) -> true; + (mnesia, _) -> false; + (A, B) -> A =< B + end, Apps0), + Apps = [{App, get_vsn(App)} || App <- Apps1], + + ERTSVersion = erlang:system_info(version), + RabbitVersion = get_vsn(rabbit), + + {release, + {"RabbitMQ", RabbitVersion}, + {erts, ERTSVersion}, + Apps}. + +get_apps(App) -> + ok = load_app(App), + {ok, DirectDeps} = application:get_key(App, applications), + lists:umerge( + [lists:usort(get_apps(Dep)) || Dep <- DirectDeps] ++ + [lists:usort([kernel, stdlib, sasl, App, mnesia])]). + +load_app(App) -> + case application:load(App) of + ok -> ok; + {error, {already_loaded, App}} -> ok + end. + +generate_rel() -> + Rel = get_rel(), + io:format("~p.~n", [Rel]), + Output = io_lib:format("~p.~n", [Rel]), + ok = file:write_file("rabbit.rel", Output). + +generate_boot() -> + Options = [local, {path, code:get_path()}], + ok = systools:make_script("rabbit", Options). + +get_vsn(App) -> + load_app(App), + {ok, Vsn} = application:get_key(App, vsn), + Vsn. diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server index 4a2737a5e3..c28755f9ce 100755 --- a/scripts/rabbitmq-server +++ b/scripts/rabbitmq-server @@ -1,4 +1,5 @@ #!/bin/sh +# vim:sw=4:et: ## 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 @@ -19,247 +20,18 @@ set -e # Get default settings with user overrides for (RABBITMQ_)<var_name> # Non-empty defaults should be set in rabbitmq-env -. `dirname $0`/rabbitmq-env - -RABBITMQ_START_RABBIT= -[ "x" = "x$RABBITMQ_ALLOW_INPUT" ] && RABBITMQ_START_RABBIT=" -noinput" -[ "x" = "x$RABBITMQ_NODE_ONLY" ] && RABBITMQ_START_RABBIT="$RABBITMQ_START_RABBIT -s $RABBITMQ_BOOT_MODULE boot " - -case "$(uname -s)" in - CYGWIN*) # we make no attempt to record the cygwin pid; rabbitmqctl wait - # will not be able to make sense of it anyway - ;; - *) # When -detached is passed, we don't write the pid, since it'd be the - # wrong one - detached="" - for opt in "$@"; do - if [ "$opt" = "-detached" ]; then - detached="true" - fi - done - if [ $detached ]; then - echo "Warning: PID file not written; -detached was passed." 1>&2 - else - RABBITMQ_PID_DIR="$(dirname ${RABBITMQ_PID_FILE})" - EX_CANTCREAT=73 # Standard exit code from sysexits(2) - if ! mkdir -p "$RABBITMQ_PID_DIR"; then - # Better diagnostics - 'mkdir -p' reports only the first directory in chain that - # it fails to create - echo "Failed to create directory: $RABBITMQ_PID_DIR" - exit $EX_CANTCREAT - fi - if ! echo $$ > ${RABBITMQ_PID_FILE}; then - # Better diagnostics - otherwise the only report in logs is about failed 'echo' - # command, but without any other details: neither what script has failed nor what - # file output was redirected to. - echo "Failed to write pid file: ${RABBITMQ_PID_FILE}" - exit $EX_CANTCREAT - fi - fi -esac - -RABBITMQ_EBIN_ROOT="${RABBITMQ_HOME}/ebin" +SCRIPTS_DIR=$(dirname "$0") +. "$SCRIPTS_DIR/rabbitmq-env" [ "$NOTIFY_SOCKET" ] && RUNNING_UNDER_SYSTEMD=true -get_noex() { - if [ "x" = "x${1}" ]; then - echo "" - else - local BASENAME=$(basename $1) - local DIRNAME=$(dirname $1) - if [ "x." = "x${DIRNAME}" ]; then - echo "${BASENAME%.*}" - else - echo "${DIRNAME}/${BASENAME%.*}" - fi - fi -} - -# Check that advanced config file has the .config extension -# Add .config extension if it's empty - -RABBITMQ_ADVANCED_CONFIG_FILE_NOEX=$(get_noex ${RABBITMQ_ADVANCED_CONFIG_FILE}) -if [ "${RABBITMQ_ADVANCED_CONFIG_FILE_NOEX}.config" = "${RABBITMQ_ADVANCED_CONFIG_FILE}" \ - -o "${RABBITMQ_ADVANCED_CONFIG_FILE_NOEX}" = "${RABBITMQ_ADVANCED_CONFIG_FILE}" ]; then - RABBITMQ_ADVANCED_CONFIG_FILE="${RABBITMQ_ADVANCED_CONFIG_FILE_NOEX}.config" -fi - - -RABBITMQ_CONFIG_FILE_NOEX=$(get_noex ${RABBITMQ_CONFIG_FILE}) -# Extension is not specified. -# Determine config type from file - -if [ "${RABBITMQ_CONFIG_FILE_NOEX}" = "${RABBITMQ_CONFIG_FILE}" ]; then - if [ -f "${RABBITMQ_CONFIG_FILE_NOEX}.config" ]; then - if [ -f "${RABBITMQ_CONFIG_FILE_NOEX}.conf" ]; then - # Both files exist. Print a warning. - _rmq_env_pwarn 'Both old (.config) and new (.conf) format config files exist.' \ - "Using the old format config file: ${RABBITMQ_CONFIG_FILE_NOEX}.config" \ - 'Please update your config files to the new format and remove the old file.' - fi - RABBITMQ_CONFIG_FILE="${RABBITMQ_CONFIG_FILE_NOEX}.config" - elif [ -f "${RABBITMQ_CONFIG_FILE_NOEX}.conf" ]; then - RABBITMQ_CONFIG_FILE="${RABBITMQ_CONFIG_FILE_NOEX}.conf" - else - if [ -f ${RABBITMQ_ADVANCED_CONFIG_FILE} ]; then - _rmq_env_pwarn "Using RABBITMQ_ADVANCED_CONFIG_FILE: ${RABBITMQ_ADVANCED_CONFIG_FILE}" - fi - # No config file exist. Use advanced config for -config arg. - RABBITMQ_CONFIG_ARG_FILE="${RABBITMQ_ADVANCED_CONFIG_FILE}" - RABBITMQ_CONFIG_FILE="" - fi -fi - -# Set the -config argument. -# The -config argument should not have extension. -# the file should exist -# the file should be a valid erlang term file - -# Config file extension is .config -if [ "${RABBITMQ_CONFIG_FILE_NOEX}.config" = "${RABBITMQ_CONFIG_FILE}" ]; then - RABBITMQ_CONFIG_ARG_FILE="${RABBITMQ_CONFIG_FILE}" -# Config file extension is .conf -elif [ "${RABBITMQ_CONFIG_FILE_NOEX}.conf" = "${RABBITMQ_CONFIG_FILE}" ]; then - RABBITMQ_CONFIG_ARG_FILE="${RABBITMQ_ADVANCED_CONFIG_FILE}" -elif [ "x" != "x${RABBITMQ_CONFIG_FILE}" \ - -a "${RABBITMQ_CONFIG_FILE_NOEX}" != "${RABBITMQ_CONFIG_FILE}" ]; then - # Config file has an extension, but it's neither .conf or .config - _rmq_env_perr "Wrong extension for RABBITMQ_CONFIG_FILE: ${RABBITMQ_CONFIG_FILE}" \ - 'The extension should be either .conf or .config' - exit 64 # EX_USAGE -fi - -RABBITMQ_CONFIG_ARG_FILE_NOEX=$(get_noex ${RABBITMQ_CONFIG_ARG_FILE}) - -if [ "${RABBITMQ_CONFIG_ARG_FILE_NOEX}.config" != "${RABBITMQ_CONFIG_ARG_FILE}" ]; then - if [ "${RABBITMQ_CONFIG_ARG_FILE}" = "${RABBITMQ_ADVANCED_CONFIG_FILE}" ]; then - _rmq_env_perr "Wrong extension for RABBITMQ_ADVANCED_CONFIG_FILE: ${RABBITMQ_ADVANCED_CONFIG_FILE}" \ - 'The extension should be .config' - exit 64 # EX_USAGE - else - # We should never got here, but still there should be some explanation - _rmq_env_perr "Wrong extension for ${RABBITMQ_CONFIG_ARG_FILE}" - 'The extension should be .config' - exit 64 # EX_USAGE - fi -fi - -# Set -config if the file exists -if [ -f "${RABBITMQ_CONFIG_ARG_FILE}" ]; then - RABBITMQ_CONFIG_ARG="-config ${RABBITMQ_CONFIG_ARG_FILE_NOEX}" -fi - -# Set -conf and other generated config parameters -if [ "${RABBITMQ_CONFIG_FILE_NOEX}.conf" = "${RABBITMQ_CONFIG_FILE}" ]; then - if [ ! -d ${RABBITMQ_SCHEMA_DIR} ]; then - mkdir -p "${RABBITMQ_SCHEMA_DIR}" - fi - - if [ ! -d ${RABBITMQ_GENERATED_CONFIG_DIR} ]; then - mkdir -p "${RABBITMQ_GENERATED_CONFIG_DIR}" - fi - - cp -f "${RABBITMQ_HOME}/priv/schema/rabbit.schema" "${RABBITMQ_SCHEMA_DIR}" - - RABBITMQ_GENERATED_CONFIG_ARG="-conf ${RABBITMQ_CONFIG_FILE} \ - -conf_dir ${RABBITMQ_GENERATED_CONFIG_DIR} \ - -conf_script_dir `dirname $0` \ - -conf_schema_dir ${RABBITMQ_SCHEMA_DIR} - -conf_advanced ${RABBITMQ_ADVANCED_CONFIG_FILE}" -fi - -set +e - -# `net_kernel:start/1` will fail in `longnames` mode when erlang is -# unable to determine FQDN of a node (with a dot in it). But `erl` -# itself has some magic that still allow it to start when you -# explicitly specify host (a.la `erl -name test@localhost`). -# -# It's not possible to communicate with this node, unless it's a -# connection initiator. But as prelaunch IS an initiator, it doesn't -# matter what we actually put here. But `localhost` sounds good -# enough. -RABBITMQ_PRELAUNCH_NODENAME="rabbitmqprelaunch${$}@localhost" - -# NOTIFY_SOCKET is needed here to prevent epmd from impersonating the -# success of our startup sequence to systemd. -NOTIFY_SOCKET= \ -RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \ -ERL_CRASH_DUMP=$ERL_CRASH_DUMP \ -RABBITMQ_CONFIG_ARG_FILE=$RABBITMQ_CONFIG_ARG_FILE \ -RABBITMQ_DIST_PORT=$RABBITMQ_DIST_PORT \ - ${ERL_DIR}erl -pa "$RABBITMQ_EBIN_ROOT" \ - -boot "${CLEAN_BOOT_FILE}" \ - -noinput \ - -hidden \ - -s rabbit_prelaunch \ - ${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS} \ - ${RABBITMQ_NAME_TYPE} ${RABBITMQ_PRELAUNCH_NODENAME} \ - -conf_advanced "${RABBITMQ_ADVANCED_CONFIG_FILE}" \ - -rabbit feature_flags_file "\"$RABBITMQ_FEATURE_FLAGS_FILE\"" \ - -rabbit enabled_plugins_file "\"$RABBITMQ_ENABLED_PLUGINS_FILE\"" \ - -rabbit plugins_dir "\"$RABBITMQ_PLUGINS_DIR\"" \ - -extra "${RABBITMQ_NODENAME}" - -PRELAUNCH_RESULT=$? -if [ ${PRELAUNCH_RESULT} = 2 ] ; then - # dist port is mentioned in config, so do not set it - true -elif [ ${PRELAUNCH_RESULT} = 0 ] ; then - # dist port is not mentioned in the config file, we can set it - RABBITMQ_DIST_ARG="-kernel inet_dist_listen_min ${RABBITMQ_DIST_PORT} -kernel inet_dist_listen_max ${RABBITMQ_DIST_PORT}" -else - exit ${PRELAUNCH_RESULT} -fi - -# The default allocation strategy RabbitMQ is using was introduced -# in Erlang/OTP 20.2.3. Earlier Erlang versions fail to start with -# this configuration. We therefore need to ensure that erl accepts -# these values before we can use them. -# -# The defaults are meant to reduce RabbitMQ's memory usage and help -# it reclaim memory at the cost of a slight decrease in performance -# (due to an increase in memory operations). These defaults can be -# overridden using the RABBITMQ_SERVER_ERL_ARGS variable. RABBITMQ_DEFAULT_ALLOC_ARGS="+MBas ageffcbf +MHas ageffcbf +MBlmbcs 512 +MHlmbcs 512 +MMmcs 30" -${ERL_DIR}erl ${RABBITMQ_DEFAULT_ALLOC_ARGS} \ - -boot "${CLEAN_BOOT_FILE}" \ - -noinput -eval 'halt(0)' 2>/dev/null - -if [ $? != 0 ] ; then - RABBITMQ_DEFAULT_ALLOC_ARGS= -fi - -set -e - -RABBITMQ_LISTEN_ARG= -[ "x" != "x$RABBITMQ_NODE_PORT" ] && [ "x" != "x$RABBITMQ_NODE_IP_ADDRESS" ] && RABBITMQ_LISTEN_ARG="-rabbit tcp_listeners [{\""${RABBITMQ_NODE_IP_ADDRESS}"\","${RABBITMQ_NODE_PORT}"}]" - -# If $RABBITMQ_LOGS is '-', send all log messages to stdout. This is -# particularly useful for Docker images. - -if [ "$RABBITMQ_LOGS" = '-' ]; then - SASL_ERROR_LOGGER=tty - RABBIT_LAGER_HANDLER=tty - RABBITMQ_LAGER_HANDLER_UPGRADE=tty -else - SASL_ERROR_LOGGER=false - RABBIT_LAGER_HANDLER='"'${RABBITMQ_LOGS}'"' - RABBITMQ_LAGER_HANDLER_UPGRADE='"'${RABBITMQ_UPGRADE_LOG}'"' -fi - # Bump ETS table limit to 50000 if [ "x" = "x$ERL_MAX_ETS_TABLES" ]; then ERL_MAX_ETS_TABLES=50000 fi -# we need to turn off path expansion because some of the vars, notably -# RABBITMQ_SERVER_ERL_ARGS, contain terms that look like globs and -# there is no other way of preventing their expansion. -set -f - # Lazy initialization of threed pool size - if it wasn't set # explicitly. This parameter is only needed when server is starting, # so it makes no sense to do this calculations in rabbitmq-env or @@ -267,70 +39,16 @@ set -f ensure_thread_pool_size() { if [ -z "${RABBITMQ_IO_THREAD_POOL_SIZE}" ]; then RABBITMQ_IO_THREAD_POOL_SIZE=$( - ${ERL_DIR}erl -pa "$RABBITMQ_EBIN_ROOT" \ - -boot "${CLEAN_BOOT_FILE}" \ - -noinput \ - -s rabbit_misc report_default_thread_pool_size + erl \ + -noinput \ + -boot "${CLEAN_BOOT_FILE}" \ + -s rabbit_misc report_default_thread_pool_size ) fi } -start_rabbitmq_server() { - # The arguments to -pa are in this order because they are *pre*-pended - # to the code path. Since we want RABBITMQ_SERVER_CODE_PATH to precede - # RABBITMQ_EBIN_ROOT, it must come as the second argument here. - # https://github.com/rabbitmq/rabbitmq-server/issues/1777 - ensure_thread_pool_size - check_start_params && - RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \ - ERL_MAX_ETS_TABLES=$ERL_MAX_ETS_TABLES \ - ERL_CRASH_DUMP=$ERL_CRASH_DUMP \ - exec ${ERL_DIR}erl \ - -pa "$RABBITMQ_EBIN_ROOT" "$RABBITMQ_SERVER_CODE_PATH" \ - ${RABBITMQ_START_RABBIT} \ - ${RABBITMQ_NAME_TYPE} ${RABBITMQ_NODENAME} \ - -boot "${SASL_BOOT_FILE}" \ - ${RABBITMQ_CONFIG_ARG} \ - ${RABBITMQ_GENERATED_CONFIG_ARG} \ - +W w \ - +A ${RABBITMQ_IO_THREAD_POOL_SIZE} \ - ${RABBITMQ_DEFAULT_ALLOC_ARGS} \ - ${RABBITMQ_SERVER_ERL_ARGS} \ - +K true \ - -kernel inet_default_connect_options "[{nodelay,true}]" \ - ${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS} \ - ${RABBITMQ_LISTEN_ARG} \ - -sasl errlog_type error \ - -sasl sasl_error_logger "$SASL_ERROR_LOGGER" \ - -rabbit lager_log_root "\"$RABBITMQ_LOG_BASE\"" \ - -rabbit lager_default_file "$RABBIT_LAGER_HANDLER" \ - -rabbit lager_upgrade_file "$RABBITMQ_LAGER_HANDLER_UPGRADE" \ - -rabbit feature_flags_file "\"$RABBITMQ_FEATURE_FLAGS_FILE\"" \ - -rabbit enabled_plugins_file "\"$RABBITMQ_ENABLED_PLUGINS_FILE\"" \ - -rabbit plugins_dir "\"$RABBITMQ_PLUGINS_DIR\"" \ - -rabbit plugins_expand_dir "\"$RABBITMQ_PLUGINS_EXPAND_DIR\"" \ - -os_mon start_cpu_sup false \ - -os_mon start_disksup false \ - -os_mon start_memsup false \ - -mnesia dir "\"${RABBITMQ_MNESIA_DIR}\"" \ - -ra data_dir "\"${RABBITMQ_QUORUM_DIR}\"" \ - ${RABBITMQ_SERVER_START_ARGS} \ - ${RABBITMQ_DIST_ARG} \ - "$@" -} - -stop_rabbitmq_server() { - RABBITMQCTL="$(dirname "$0")/rabbitmqctl" - - if ${RABBITMQCTL} -n ${RABBITMQ_NODENAME} status >/dev/null 2>&1; then - ${RABBITMQCTL} -n ${RABBITMQ_NODENAME} stop - fi -} - check_start_params() { check_not_empty RABBITMQ_BOOT_MODULE - check_not_empty RABBITMQ_NAME_TYPE - check_not_empty RABBITMQ_NODENAME check_not_empty SASL_BOOT_FILE check_not_empty RABBITMQ_IO_THREAD_POOL_SIZE } @@ -346,6 +64,61 @@ check_not_empty() { fi } +start_rabbitmq_server() { + set -e + + _rmq_env_set_erl_libs + ensure_thread_pool_size + + RABBITMQ_START_RABBIT= + [ "x" = "x$RABBITMQ_ALLOW_INPUT" ] && RABBITMQ_START_RABBIT=" -noinput" + if test -z "$RABBITMQ_NODE_ONLY"; then + if test "$USE_RABBIT_BOOT_SCRIPT"; then + # TODO: This is experimental and undocumented at this point. + # It is here just to do simple checks while playing with how + # RabbitMQ is started. + "$SCRIPTS_DIR/rabbitmq-rel" gen-boot + SASL_BOOT_FILE=rabbit + test -f "$SASL_BOOT_FILE.boot" + RABBITMQ_START_RABBIT="$RABBITMQ_START_RABBIT -init_debug" + else + RABBITMQ_START_RABBIT="$RABBITMQ_START_RABBIT -s $RABBITMQ_BOOT_MODULE boot" + fi + fi + + # We need to turn off path expansion because some of the vars, + # notably RABBITMQ_SERVER_ERL_ARGS, contain terms that look like + # globs and there is no other way of preventing their expansion. + set -f + + export ERL_MAX_ETS_TABLES \ + SYS_PREFIX + + check_start_params + + exec erl \ + -pa "$RABBITMQ_SERVER_CODE_PATH" \ + ${RABBITMQ_START_RABBIT} \ + -boot "${SASL_BOOT_FILE}" \ + +W w \ + +K true \ + +A ${RABBITMQ_IO_THREAD_POOL_SIZE} \ + ${RABBITMQ_DEFAULT_ALLOC_ARGS} \ + ${RABBITMQ_SERVER_ERL_ARGS} \ + ${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS} \ + ${RABBITMQ_SERVER_START_ARGS} \ + -lager crash_log false \ + -lager handlers '[]' \ + "$@" +} + +stop_rabbitmq_server() { + if test "$rabbitmq_server_pid"; then + kill -TERM "$rabbitmq_server_pid" + wait "$rabbitmq_server_pid" || true + fi +} + if [ "$RABBITMQ_ALLOW_INPUT" -o "$RUNNING_UNDER_SYSTEMD" -o "$detached" ]; then # Run erlang VM directly, completely replacing current shell # process - so the pid file written in the code above will be @@ -381,7 +154,7 @@ else trap "stop_rabbitmq_server; exit 130" INT start_rabbitmq_server "$@" & - rabbitmq_server_pid=$! + export rabbitmq_server_pid=$! # Block until RabbitMQ exits or a signal is caught. # Waits for last command (which is start_rabbitmq_server) @@ -399,5 +172,5 @@ else # force that statement to succeed and the signal handler to properly # execute. Because the statement below has an exit code of 0, the # signal handler has to restate the expected exit code. - wait $rabbitmq_server_pid || true + wait "$rabbitmq_server_pid" || true fi diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat index 7d4d1b486f..57cbdf9392 100644 --- a/scripts/rabbitmq-server.bat +++ b/scripts/rabbitmq-server.bat @@ -46,163 +46,8 @@ if not exist "!ERLANG_HOME!\bin\erl.exe" ( exit /B 1
)
-set RABBITMQ_EBIN_ROOT=!RABBITMQ_HOME!\ebin
-
-CALL :convert_forward_slashes "!RABBITMQ_ADVANCED_CONFIG_FILE!" RABBITMQ_ADVANCED_CONFIG_FILE
-CALL :get_noex "!RABBITMQ_ADVANCED_CONFIG_FILE!" RABBITMQ_ADVANCED_CONFIG_FILE_NOEX
-
-if "!RABBITMQ_ADVANCED_CONFIG_FILE!" == "!RABBITMQ_ADVANCED_CONFIG_FILE_NOEX!" (
- set RABBITMQ_ADVANCED_CONFIG_FILE=!RABBITMQ_ADVANCED_CONFIG_FILE_NOEX!.config
- REM Try to create advanced config file, if it doesn't exist
- REM It still can fail to be created, but at least not for default install
- if not exist "!RABBITMQ_ADVANCED_CONFIG_FILE!" (
- echo []. > !RABBITMQ_ADVANCED_CONFIG_FILE!
- )
-)
-
-CALL :convert_forward_slashes "!RABBITMQ_CONFIG_FILE!" RABBITMQ_CONFIG_FILE
-CALL :get_noex "!RABBITMQ_CONFIG_FILE!" RABBITMQ_CONFIG_FILE_NOEX
-
-if "!RABBITMQ_CONFIG_FILE!" == "!RABBITMQ_CONFIG_FILE_NOEX!" (
- if exist "!RABBITMQ_CONFIG_FILE_NOEX!.config" (
- if exist "!RABBITMQ_CONFIG_FILE_NOEX!.conf" (
- rem Both files exist. Print a warning
- echo "WARNING: Both old (.config) and new (.conf) format config files exist."
- echo "WARNING: Using the old format config file: !RABBITMQ_CONFIG_FILE_NOEX!.config"
- echo "WARNING: Please update your config files to the new format and remove the old file"
- )
- set RABBITMQ_CONFIG_FILE=!RABBITMQ_CONFIG_FILE_NOEX!.config
- ) else if exist "!RABBITMQ_CONFIG_FILE_NOEX!.conf" (
- set RABBITMQ_CONFIG_FILE=!RABBITMQ_CONFIG_FILE_NOEX!.conf
- ) else (
- rem No config file exist. Use advanced config for -config arg.
- if exist "!RABBITMQ_ADVANCED_CONFIG_FILE!" (
- echo "WARNING: Using RABBITMQ_ADVANCED_CONFIG_FILE: !RABBITMQ_ADVANCED_CONFIG_FILE!"
- )
- set RABBITMQ_CONFIG_ARG_FILE=!RABBITMQ_ADVANCED_CONFIG_FILE!
- )
-)
-
-rem Set the -config argument.
-rem The -config argument should not have extension.
-rem the file should exist
-rem the file should be a valid erlang term file
-
-rem Config file extension is .config
-if "!RABBITMQ_CONFIG_FILE_NOEX!.config" == "!RABBITMQ_CONFIG_FILE!" (
- set RABBITMQ_CONFIG_ARG_FILE=!RABBITMQ_CONFIG_FILE!
-) else if "!RABBITMQ_CONFIG_FILE_NOEX!.conf" == "!RABBITMQ_CONFIG_FILE!" (
- set RABBITMQ_CONFIG_ARG_FILE=!RABBITMQ_ADVANCED_CONFIG_FILE!
-) else if not "" == "!RABBITMQ_CONFIG_FILE!" (
- if not "!RABBITMQ_CONFIG_FILE_NOEX!" == "!RABBITMQ_CONFIG_FILE!" (
- rem Config file has an extension, but it's neither .conf or .config
- echo "ERROR: Wrong extension for RABBITMQ_CONFIG_FILE: !RABBITMQ_CONFIG_FILE!"
- echo "ERROR: extension should be either .conf or .config"
- exit /B 1
- )
-)
-
-CALL :convert_forward_slashes "!RABBITMQ_CONFIG_ARG_FILE!" RABBITMQ_CONFIG_ARG_FILE
-CALL :get_noex "!RABBITMQ_CONFIG_ARG_FILE!" RABBITMQ_CONFIG_ARG_FILE_NOEX
-
-if not "!RABBITMQ_CONFIG_ARG_FILE_NOEX!.config" == "!RABBITMQ_CONFIG_ARG_FILE!" (
- if "!RABBITMQ_CONFIG_ARG_FILE!" == "!RABBITMQ_ADVANCED_CONFIG_FILE!" (
- echo "ERROR: Wrong extension for RABBITMQ_ADVANCED_CONFIG_FILE: !RABBITMQ_ADVANCED_CONFIG_FILE!"
- echo "ERROR: extension should be .config"
- exit /B 1
- ) else (
- rem We should never got here, but still there should be some explanation
- echo "ERROR: Wrong extension for !RABBITMQ_CONFIG_ARG_FILE!"
- echo "ERROR: extension should be .config"
- exit /B 1
- )
-)
-
-rem Set -config if the file exists
-if exist !RABBITMQ_CONFIG_ARG_FILE! (
- set RABBITMQ_CONFIG_ARG=-config "!RABBITMQ_CONFIG_ARG_FILE_NOEX!"
-)
-
-rem Set -conf and other generated config parameters
-if "!RABBITMQ_CONFIG_FILE_NOEX!.conf" == "!RABBITMQ_CONFIG_FILE!" (
- if not exist "!RABBITMQ_SCHEMA_DIR!" (
- mkdir "!RABBITMQ_SCHEMA_DIR!"
- )
-
- if not exist "!RABBITMQ_GENERATED_CONFIG_DIR!" (
- mkdir "!RABBITMQ_GENERATED_CONFIG_DIR!"
- )
-
- copy /Y "!RABBITMQ_HOME!\priv\schema\rabbit.schema" "!RABBITMQ_SCHEMA_DIR!\rabbit.schema"
-
- set RABBITMQ_GENERATED_CONFIG_ARG=-conf "!RABBITMQ_CONFIG_FILE:\=/!" ^
- -conf_dir "!RABBITMQ_GENERATED_CONFIG_DIR:\=/!" ^
- -conf_script_dir "!CONF_SCRIPT_DIR:\=/!" ^
- -conf_schema_dir "!RABBITMQ_SCHEMA_DIR:\=/!" ^
- -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE:\=/!"
-)
-
-"!ERLANG_HOME!\bin\erl.exe" ^
- -pa "!RABBITMQ_EBIN_ROOT:\=/!" ^
- -boot !CLEAN_BOOT_FILE! ^
- -noinput -hidden ^
- -s rabbit_prelaunch ^
- !RABBITMQ_NAME_TYPE! rabbitmqprelaunch!RANDOM!!TIME:~9!@localhost ^
- -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE!" ^
- -rabbit feature_flags_file "!RABBITMQ_FEATURE_FLAGS_FILE!" ^
- -rabbit enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" ^
- -rabbit plugins_dir "!RABBITMQ_PLUGINS_DIR!" ^
- -extra "!RABBITMQ_NODENAME!"
-
-if ERRORLEVEL 2 (
- rem dist port mentioned in config, do not attempt to set it
-) else if ERRORLEVEL 1 (
- exit /B 1
-) else (
- set RABBITMQ_DIST_ARG=-kernel inet_dist_listen_min !RABBITMQ_DIST_PORT! -kernel inet_dist_listen_max !RABBITMQ_DIST_PORT!
-)
-
-rem The default allocation strategy RabbitMQ is using was introduced
-rem in Erlang/OTP 20.2.3. Earlier Erlang versions fail to start with
-rem this configuration. We therefore need to ensure that erl accepts
-rem these values before we can use them.
-rem
-rem The defaults are meant to reduce RabbitMQ's memory usage and help
-rem it reclaim memory at the cost of a slight decrease in performance
-rem (due to an increase in memory operations). These defaults can be
-rem overridden using the RABBITMQ_SERVER_ERL_ARGS variable.
-
set RABBITMQ_DEFAULT_ALLOC_ARGS=+MBas ageffcbf +MHas ageffcbf +MBlmbcs 512 +MHlmbcs 512 +MMmcs 30
-"!ERLANG_HOME!\bin\erl.exe" ^
- !RABBITMQ_DEFAULT_ALLOC_ARGS! ^
- -boot !CLEAN_BOOT_FILE! ^
- -noinput -eval "halt(0)"
-
-if ERRORLEVEL 1 (
- set RABBITMQ_DEFAULT_ALLOC_ARGS=
-)
-
-set RABBITMQ_LISTEN_ARG=
-if not "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
- if not "!RABBITMQ_NODE_PORT!"=="" (
- set RABBITMQ_LISTEN_ARG=-rabbit tcp_listeners [{"\"!RABBITMQ_NODE_IP_ADDRESS!\"","!RABBITMQ_NODE_PORT!"}]
- )
-)
-
-REM If !RABBITMQ_LOGS! is '-', send all log messages to stdout. This is
-REM particularly useful for Docker images.
-
-if "!RABBITMQ_LOGS!" == "-" (
- set SASL_ERROR_LOGGER=tty
- set RABBIT_LAGER_HANDLER=tty
- set RABBITMQ_LAGER_HANDLER_UPGRADE=tty
-) else (
- set SASL_ERROR_LOGGER=false
- set RABBIT_LAGER_HANDLER="\"!RABBITMQ_LOGS:\=/!\""
- set RABBITMQ_LAGER_HANDLER_UPGRADE="\"!RABBITMQ_UPGRADE_LOG:\=/!\""
-)
-
set RABBITMQ_START_RABBIT=
if "!RABBITMQ_ALLOW_INPUT!"=="" (
set RABBITMQ_START_RABBIT=!RABBITMQ_START_RABBIT! -noinput
@@ -217,9 +62,6 @@ if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" ( set ENV_OK=true
CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE!
-CALL :check_not_empty "RABBITMQ_NAME_TYPE" !RABBITMQ_NAME_TYPE!
-CALL :check_not_empty "RABBITMQ_NODENAME" !RABBITMQ_NODENAME!
-
if "!ENV_OK!"=="false" (
EXIT /b 78
@@ -232,35 +74,16 @@ if "!RABBITMQ_ALLOW_INPUT!"=="" ( )
"!ERLANG_HOME!\bin\!ERL_CMD!" ^
--pa "!RABBITMQ_EBIN_ROOT:\=/!" ^
--boot start_sasl ^
!RABBITMQ_START_RABBIT! ^
-!RABBITMQ_CONFIG_ARG! ^
-!RABBITMQ_GENERATED_CONFIG_ARG! ^
-!RABBITMQ_NAME_TYPE! !RABBITMQ_NODENAME! ^
+-boot "!SASL_BOOT_FILE!" ^
+W w ^
+A "!RABBITMQ_IO_THREAD_POOL_SIZE!" ^
!RABBITMQ_DEFAULT_ALLOC_ARGS! ^
!RABBITMQ_SERVER_ERL_ARGS! ^
-!RABBITMQ_LISTEN_ARG! ^
--kernel inet_default_connect_options "[{nodelay, true}]" ^
!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^
--sasl errlog_type error ^
--sasl sasl_error_logger !SASL_ERROR_LOGGER! ^
--rabbit lager_log_root "\"!RABBITMQ_LOG_BASE:\=/!\"" ^
--rabbit lager_default_file !RABBIT_LAGER_HANDLER! ^
--rabbit lager_upgrade_file !RABBITMQ_LAGER_HANDLER_UPGRADE! ^
--rabbit feature_flags_file "\"!RABBITMQ_FEATURE_FLAGS_FILE:\=/!\"" ^
--rabbit enabled_plugins_file "\"!RABBITMQ_ENABLED_PLUGINS_FILE:\=/!\"" ^
--rabbit plugins_dir "\"!RABBITMQ_PLUGINS_DIR:\=/!\"" ^
--rabbit plugins_expand_dir "\"!RABBITMQ_PLUGINS_EXPAND_DIR:\=/!\"" ^
--mnesia dir "\"!RABBITMQ_MNESIA_DIR:\=/!\"" ^
--os_mon start_cpu_sup false ^
--os_mon start_disksup false ^
--os_mon start_memsup false ^
--ra data_dir \""!RABBITMQ_QUORUM_DIR:\=/!"\" ^
!RABBITMQ_SERVER_START_ARGS! ^
-!RABBITMQ_DIST_ARG! ^
+-lager crash_log false ^
+-lager handlers "[]" ^
!STAR!
if ERRORLEVEL 1 (
@@ -277,17 +100,6 @@ if "%~2"=="" ( )
EXIT /B 0
-:get_noex
-set "%~2=%~dpn1"
-EXIT /B 0
-
-rem Convert unix style path separators into windows style path separators
-rem needed for comparing with _NOEX variables
-rem rabbitmq/rabbitmq-server#1962
-:convert_forward_slashes
-set "%~2=%~dpf1"
-EXIT /B 0
-
endlocal
endlocal
endlocal
diff --git a/scripts/rabbitmq-service.bat b/scripts/rabbitmq-service.bat index fe9884abf0..e9ee0ea74b 100644 --- a/scripts/rabbitmq-service.bat +++ b/scripts/rabbitmq-service.bat @@ -35,6 +35,38 @@ REM Get default settings with user overrides for (RABBITMQ_)<var_name> REM Non-empty defaults should be set in rabbitmq-env
call "%TDP0%\rabbitmq-env.bat" %~n0
+REM Check for the short names here too
+if "!RABBITMQ_USE_LONGNAME!"=="true" (
+ set RABBITMQ_NAME_TYPE=-name
+ set NAMETYPE=longnames
+) else (
+ if "!USE_LONGNAME!"=="true" (
+ set RABBITMQ_USE_LONGNAME=true
+ set RABBITMQ_NAME_TYPE=-name
+ set NAMETYPE=longnames
+ ) else (
+ set RABBITMQ_USE_LONGNAME=false
+ set RABBITMQ_NAME_TYPE=-sname
+ set NAMETYPE=shortnames
+ )
+)
+
+REM [ "x" = "x$RABBITMQ_NODENAME" ] && RABBITMQ_NODENAME=${NODENAME}
+if "!RABBITMQ_NODENAME!"=="" (
+ if "!NODENAME!"=="" (
+ REM We use Erlang to query the local hostname because
+ REM !COMPUTERNAME! and Erlang may return different results.
+ REM Start erl with -sname to make sure epmd is started.
+ call "%ERLANG_HOME%\bin\erl.exe" -A0 -noinput -boot start_clean -sname rabbit-prelaunch-epmd -eval "init:stop()." >nul 2>&1
+ for /f "delims=" %%F in ('call "%ERLANG_HOME%\bin\erl.exe" -A0 -noinput -boot start_clean -eval "net_kernel:start([list_to_atom(""rabbit-gethostname-"" ++ os:getpid()), %NAMETYPE%]), [_, H] = string:tokens(atom_to_list(node()), ""@""), io:format(""~s~n"", [H]), init:stop()."') do @set HOSTNAME=%%F
+ set RABBITMQ_NODENAME=rabbit@!HOSTNAME!
+ set HOSTNAME=
+ ) else (
+ set RABBITMQ_NODENAME=!NODENAME!
+ )
+)
+set NAMETYPE=
+
set STARVAR=
shift
:loop1
@@ -112,16 +144,6 @@ if not exist "!RABBITMQ_BASE!" ( echo Creating base directory !RABBITMQ_BASE! & mkdir "!RABBITMQ_BASE!"
)
-set ENV_OK=true
-CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE!
-CALL :check_not_empty "RABBITMQ_NAME_TYPE" !RABBITMQ_NAME_TYPE!
-CALL :check_not_empty "RABBITMQ_NODENAME" !RABBITMQ_NODENAME!
-
-
-if "!ENV_OK!"=="false" (
- EXIT /b 78
-)
-
"!ERLANG_SERVICE_MANAGER_PATH!\erlsrv" list !RABBITMQ_SERVICENAME! 2>NUL 1>NUL
if errorlevel 1 (
"!ERLANG_SERVICE_MANAGER_PATH!\erlsrv" add !RABBITMQ_SERVICENAME! -internalservicename !RABBITMQ_SERVICENAME!
@@ -129,165 +151,8 @@ if errorlevel 1 ( echo !RABBITMQ_SERVICENAME! service is already present - only updating service parameters
)
-set RABBITMQ_EBIN_ROOT=!RABBITMQ_HOME!\ebin
-
-CALL :convert_forward_slashes "!RABBITMQ_ADVANCED_CONFIG_FILE!" RABBITMQ_ADVANCED_CONFIG_FILE
-CALL :get_noex "!RABBITMQ_ADVANCED_CONFIG_FILE!" RABBITMQ_ADVANCED_CONFIG_FILE_NOEX
-
-if "!RABBITMQ_ADVANCED_CONFIG_FILE!" == "!RABBITMQ_ADVANCED_CONFIG_FILE_NOEX!" (
- set RABBITMQ_ADVANCED_CONFIG_FILE=!RABBITMQ_ADVANCED_CONFIG_FILE_NOEX!.config
- REM Try to create advanced config file, if it doesn't exist
- REM It still can fail to be created, but at least not for default install
- if not exist "!RABBITMQ_ADVANCED_CONFIG_FILE!" (
- echo []. > !RABBITMQ_ADVANCED_CONFIG_FILE!
- )
-)
-
-CALL :convert_forward_slashes "!RABBITMQ_CONFIG_FILE!" RABBITMQ_CONFIG_FILE
-CALL :get_noex "!RABBITMQ_CONFIG_FILE!" RABBITMQ_CONFIG_FILE_NOEX
-
-if "!RABBITMQ_CONFIG_FILE!" == "!RABBITMQ_CONFIG_FILE_NOEX!" (
- if exist "!RABBITMQ_CONFIG_FILE_NOEX!.config" (
- if exist "!RABBITMQ_CONFIG_FILE_NOEX!.conf" (
- rem Both files exist. Print a warning
- echo "WARNING: Both old (.config) and new (.conf) format config files exist."
- echo "WARNING: Using the old format config file: !RABBITMQ_CONFIG_FILE_NOEX!.config"
- echo "WARNING: Please update your config files to the new format and remove the old file"
- )
- set RABBITMQ_CONFIG_FILE=!RABBITMQ_CONFIG_FILE_NOEX!.config
- ) else if exist "!RABBITMQ_CONFIG_FILE_NOEX!.conf" (
- set RABBITMQ_CONFIG_FILE=!RABBITMQ_CONFIG_FILE_NOEX!.conf
- ) else (
- rem No config file exist. Use advanced config for -config arg.
- if exist "!RABBITMQ_ADVANCED_CONFIG_FILE!" (
- echo "WARNING: Using RABBITMQ_ADVANCED_CONFIG_FILE: !RABBITMQ_ADVANCED_CONFIG_FILE!"
- )
- set RABBITMQ_CONFIG_ARG_FILE=!RABBITMQ_ADVANCED_CONFIG_FILE!
- )
-)
-
-rem Set the -config argument.
-rem The -config argument should not have extension.
-rem the file should exist
-rem the file should be a valid erlang term file
-
-rem Config file extension is .config
-if "!RABBITMQ_CONFIG_FILE_NOEX!.config" == "!RABBITMQ_CONFIG_FILE!" (
- set RABBITMQ_CONFIG_ARG_FILE=!RABBITMQ_CONFIG_FILE!
-) else if "!RABBITMQ_CONFIG_FILE_NOEX!.conf" == "!RABBITMQ_CONFIG_FILE!" (
- set RABBITMQ_CONFIG_ARG_FILE=!RABBITMQ_ADVANCED_CONFIG_FILE!
-) else if not "" == "!RABBITMQ_CONFIG_FILE!" (
- if not "!RABBITMQ_CONFIG_FILE_NOEX!" == "!RABBITMQ_CONFIG_FILE!" (
- rem Config file has an extension, but it's neither .conf or .config
- echo "ERROR: Wrong extension for RABBITMQ_CONFIG_FILE: !RABBITMQ_CONFIG_FILE!"
- echo "ERROR: extension should be either .conf or .config"
- exit /B 1
- )
-)
-
-CALL :convert_forward_slashes "!RABBITMQ_CONFIG_ARG_FILE!" RABBITMQ_CONFIG_ARG_FILE
-CALL :get_noex "!RABBITMQ_CONFIG_ARG_FILE!" RABBITMQ_CONFIG_ARG_FILE_NOEX
-
-if not "!RABBITMQ_CONFIG_ARG_FILE_NOEX!.config" == "!RABBITMQ_CONFIG_ARG_FILE!" (
- if "!RABBITMQ_CONFIG_ARG_FILE!" == "!RABBITMQ_ADVANCED_CONFIG_FILE!" (
- echo "ERROR: Wrong extension for RABBITMQ_ADVANCED_CONFIG_FILE: !RABBITMQ_ADVANCED_CONFIG_FILE!"
- echo "ERROR: extension should be .config"
- exit /B 1
- ) else (
- rem We should never got here, but still there should be some explanation
- echo "ERROR: Wrong extension for !RABBITMQ_CONFIG_ARG_FILE!"
- echo "ERROR: extension should be .config"
- exit /B 1
- )
-)
-
-rem Set -config if the file exists
-if exist !RABBITMQ_CONFIG_ARG_FILE! (
- set RABBITMQ_CONFIG_ARG=-config "!RABBITMQ_CONFIG_ARG_FILE_NOEX!"
-)
-
-rem Set -conf and other generated config parameters
-if "!RABBITMQ_CONFIG_FILE_NOEX!.conf" == "!RABBITMQ_CONFIG_FILE!" (
- if not exist "!RABBITMQ_SCHEMA_DIR!" (
- mkdir "!RABBITMQ_SCHEMA_DIR!"
- )
-
- if not exist "!RABBITMQ_GENERATED_CONFIG_DIR!" (
- mkdir "!RABBITMQ_GENERATED_CONFIG_DIR!"
- )
-
- copy /Y "!RABBITMQ_HOME!\priv\schema\rabbit.schema" "!RABBITMQ_SCHEMA_DIR!\rabbit.schema"
-
- set RABBITMQ_GENERATED_CONFIG_ARG=-conf "!RABBITMQ_CONFIG_FILE:\=/!" ^
- -conf_dir "!RABBITMQ_GENERATED_CONFIG_DIR:\=/!" ^
- -conf_script_dir "!CONF_SCRIPT_DIR:\=/!" ^
- -conf_schema_dir "!RABBITMQ_SCHEMA_DIR:\=/!" ^
- -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE:\=/!"
-)
-
-"!ERLANG_HOME!\bin\erl.exe" ^
- -pa "!RABBITMQ_EBIN_ROOT:\=/!" ^
- -boot !CLEAN_BOOT_FILE! ^
- -noinput -hidden ^
- -s rabbit_prelaunch ^
- !RABBITMQ_NAME_TYPE! rabbitmqprelaunch!RANDOM!!TIME:~9!@localhost ^
- -conf_advanced "!RABBITMQ_ADVANCED_CONFIG_FILE!" ^
- -rabbit feature_flags_file "!RABBITMQ_FEATURE_FLAGS_FILE!" ^
- -rabbit enabled_plugins_file "!RABBITMQ_ENABLED_PLUGINS_FILE!" ^
- -rabbit plugins_dir "!RABBITMQ_PLUGINS_DIR!" ^
- -extra "!RABBITMQ_NODENAME!"
-
-if ERRORLEVEL 3 (
- rem ERRORLEVEL means (or greater) so we need to catch all other failure
- rem cases here
- exit /B 1
-) else if ERRORLEVEL 2 (
- rem dist port mentioned in config, do not attempt to set it
-) else if ERRORLEVEL 1 (
- exit /B 1
-) else (
- set RABBITMQ_DIST_ARG=-kernel inet_dist_listen_min !RABBITMQ_DIST_PORT! -kernel inet_dist_listen_max !RABBITMQ_DIST_PORT!
-)
-
-rem The default allocation strategy RabbitMQ is using was introduced
-rem in Erlang/OTP 20.2.3. Earlier Erlang versions fail to start with
-rem this configuration. We therefore need to ensure that erl accepts
-rem these values before we can use them.
-rem
-rem The defaults are meant to reduce RabbitMQ's memory usage and help
-rem it reclaim memory at the cost of a slight decrease in performance
-rem (due to an increase in memory operations). These defaults can be
-rem overridden using the RABBITMQ_SERVER_ERL_ARGS variable.
-
set RABBITMQ_DEFAULT_ALLOC_ARGS=+MBas ageffcbf +MHas ageffcbf +MBlmbcs 512 +MHlmbcs 512 +MMmcs 30
-"!ERLANG_HOME!\bin\erl.exe" ^
- !RABBITMQ_DEFAULT_ALLOC_ARGS! ^
- -boot !CLEAN_BOOT_FILE! ^
- -noinput -eval "halt(0)"
-
-if ERRORLEVEL 1 (
- set RABBITMQ_DEFAULT_ALLOC_ARGS=
-)
-
-
-set RABBITMQ_LISTEN_ARG=
-if not "!RABBITMQ_NODE_IP_ADDRESS!"=="" (
- if not "!RABBITMQ_NODE_PORT!"=="" (
- set RABBITMQ_LISTEN_ARG=-rabbit tcp_listeners "[{\"!RABBITMQ_NODE_IP_ADDRESS!\", !RABBITMQ_NODE_PORT!}]"
- )
-)
-
-if "!RABBITMQ_LOGS!" == "-" (
- set SASL_ERROR_LOGGER=tty
- set RABBIT_LAGER_HANDLER=tty
- set RABBITMQ_LAGER_HANDLER_UPGRADE=tty
-) else (
- set SASL_ERROR_LOGGER=false
- set RABBIT_LAGER_HANDLER="\"!RABBITMQ_LOGS:\=/!\""
- set RABBITMQ_LAGER_HANDLER_UPGRADE="\"!RABBITMQ_UPGRADE_LOG:\=/!\""
-)
-
set RABBITMQ_START_RABBIT=
if "!RABBITMQ_NODE_ONLY!"=="" (
set RABBITMQ_START_RABBIT=-s "!RABBITMQ_BOOT_MODULE!" boot
@@ -301,45 +166,46 @@ if "!RABBITMQ_SERVICE_RESTART!"=="" ( set RABBITMQ_SERVICE_RESTART=restart
)
+set ENV_OK=true
+CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE!
+CALL :check_not_empty "RABBITMQ_NAME_TYPE" !RABBITMQ_NAME_TYPE!
+CALL :check_not_empty "RABBITMQ_NODENAME" !RABBITMQ_NODENAME!
+
+if "!ENV_OK!"=="false" (
+ EXIT /b 78
+)
+
set ERLANG_SERVICE_ARGUMENTS= ^
--pa "!RABBITMQ_EBIN_ROOT:\=/!" ^
--boot start_sasl ^
!RABBITMQ_START_RABBIT! ^
-!RABBITMQ_CONFIG_ARG! ^
-!RABBITMQ_GENERATED_CONFIG_ARG! ^
+-boot "!SASL_BOOT_FILE!" ^
+W w ^
+A "!RABBITMQ_IO_THREAD_POOL_SIZE!" ^
!RABBITMQ_DEFAULT_ALLOC_ARGS! ^
!RABBITMQ_SERVER_ERL_ARGS! ^
-!RABBITMQ_LISTEN_ARG! ^
--kernel inet_default_connect_options "[{nodelay,true}]" ^
!RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS! ^
--sasl errlog_type error ^
--sasl sasl_error_logger false ^
--rabbit lager_log_root "\"!RABBITMQ_LOG_BASE:\=/!\"" ^
--rabbit lager_default_file !RABBIT_LAGER_HANDLER! ^
--rabbit lager_upgrade_file !RABBITMQ_LAGER_HANDLER_UPGRADE! ^
--rabbit feature_flags_file "\"!RABBITMQ_FEATURE_FLAGS_FILE:\=/!\"" ^
--rabbit enabled_plugins_file "\"!RABBITMQ_ENABLED_PLUGINS_FILE:\=/!\"" ^
--rabbit plugins_dir "\"!RABBITMQ_PLUGINS_DIR:\=/!\"" ^
--rabbit plugins_expand_dir "\"!RABBITMQ_PLUGINS_EXPAND_DIR:\=/!\"" ^
--rabbit windows_service_config "\"!RABBITMQ_CONFIG_FILE:\=/!\"" ^
--mnesia dir "\"!RABBITMQ_MNESIA_DIR:\=/!\"" ^
--os_mon start_cpu_sup false ^
--os_mon start_disksup false ^
--os_mon start_memsup false ^
--ra data_dir \""!RABBITMQ_QUORUM_DIR:\=/!"\" ^
!RABBITMQ_SERVER_START_ARGS! ^
-!RABBITMQ_DIST_ARG! ^
+-lager crash_log false ^
+-lager handlers "[]" ^
!STARVAR!
set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:\=\\!
set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:"=\"!
+rem We resolve %APPDATA% at install time so that the user's %APPDATA%
+rem is passed to `rabbit_env` at runtime (instead of the service's
+rem %APPDAT%).
+rem
+rem The goal is to keep the same behavior as when RabbitMQ data
+rem locations were decided in `rabbitmq-env.bat` (sourced by this
+rem script), even if now, we compute everything in `rabbit_env` at
+rem runtime.
+rem
+rem We may revisit this in the future so that no data is stored in a
+rem user-specific directory.
"!ERLANG_SERVICE_MANAGER_PATH!\erlsrv" set !RABBITMQ_SERVICENAME! ^
-onfail !RABBITMQ_SERVICE_RESTART! ^
-machine "!ERLANG_SERVICE_MANAGER_PATH!\erl.exe" ^
--env ERL_CRASH_DUMP="!RABBITMQ_BASE:\=/!/erl_crash.dump" ^
+-env APPDATA="!APPDATA!" ^
-env ERL_LIBS="!ERL_LIBS!" ^
-env ERL_MAX_ETS_TABLES="!ERL_MAX_ETS_TABLES!" ^
-env ERL_MAX_PORTS="!ERL_MAX_PORTS!" ^
@@ -386,17 +252,6 @@ if "%~2"=="" ( )
EXIT /B 0
-:get_noex
-set "%~2=%~dpn1"
-EXIT /B 0
-
-rem Convert unix style path separators into windows style path separators
-rem needed for comparing with _NOEX variables
-rem rabbitmq/rabbitmq-server#1962
-:convert_forward_slashes
-set "%~2=%~dpf1"
-EXIT /B 0
-
endlocal
endlocal
endlocal
diff --git a/scripts/rabbitmq-upgrade.bat b/scripts/rabbitmq-upgrade.bat index 921150b26b..0b9c42cc8f 100644 --- a/scripts/rabbitmq-upgrade.bat +++ b/scripts/rabbitmq-upgrade.bat @@ -49,11 +49,6 @@ if not defined ERL_CRASH_DUMP_SECONDS ( -boot !CLEAN_BOOT_FILE! ^ -noinput -noshell -hidden -smp enable ^ !RABBITMQ_CTL_ERL_ARGS! ^ --kernel inet_dist_listen_min !RABBITMQ_CTL_DIST_PORT_MIN! ^ --kernel inet_dist_listen_max !RABBITMQ_CTL_DIST_PORT_MAX! ^ --sasl errlog_type error ^ --mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^ --nodename !RABBITMQ_NODENAME! ^ -run escript start ^ -escript main rabbitmqctl_escript ^ -extra "%RABBITMQ_HOME%\escript\rabbitmq-upgrade" !STAR! @@ -62,5 +57,6 @@ if ERRORLEVEL 1 ( exit /B %ERRORLEVEL% ) -endlocal +EXIT /B 0 + endlocal diff --git a/scripts/rabbitmqctl.bat b/scripts/rabbitmqctl.bat index 08c1433154..4d9ea8d908 100644 --- a/scripts/rabbitmqctl.bat +++ b/scripts/rabbitmqctl.bat @@ -49,10 +49,6 @@ if not defined ERL_CRASH_DUMP_SECONDS ( -boot !CLEAN_BOOT_FILE! ^
-noinput -noshell -hidden -smp enable ^
!RABBITMQ_CTL_ERL_ARGS! ^
--kernel inet_dist_listen_min !RABBITMQ_CTL_DIST_PORT_MIN! ^
--kernel inet_dist_listen_max !RABBITMQ_CTL_DIST_PORT_MAX! ^
--sasl errlog_type error ^
--mnesia dir \""!RABBITMQ_MNESIA_DIR:\=/!"\" ^
-run escript start ^
-escript main rabbitmqctl_escript ^
-extra "%RABBITMQ_HOME%\escript\rabbitmqctl" !STAR!
@@ -61,5 +57,7 @@ if ERRORLEVEL 1 ( exit /B %ERRORLEVEL%
)
+EXIT /B 0
+
endlocal
endlocal
diff --git a/src/rabbit.erl b/src/rabbit.erl index e4d2ee9808..0b002618e5 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -30,15 +30,9 @@ -export([start/2, stop/1, prep_stop/1]). -export([start_apps/1, start_apps/2, stop_apps/1]). --export([log_locations/0, config_files/0, decrypt_config/2]). %% for testing and mgmt-agent +-export([log_locations/0, config_files/0]). %% for testing and mgmt-agent -export([is_booted/1, is_booted/0, is_booting/1, is_booting/0]). --ifdef(TEST). - --export([start_logger/0]). - --endif. - %%--------------------------------------------------------------------------- %% Boot steps. -export([maybe_insert_default_data/0, boot_delegate/0, recover/0]). @@ -262,7 +256,7 @@ -include("rabbit_framing.hrl"). -include("rabbit.hrl"). --define(APPS, [os_mon, mnesia, rabbit_common, ra, sysmon_handler, rabbit]). +-define(APPS, [os_mon, mnesia, rabbit_common, rabbitmq_prelaunch, ra, sysmon_handler, rabbit]). -define(ASYNC_THREADS_WARNING_THRESHOLD, 8). @@ -282,75 +276,93 @@ %%---------------------------------------------------------------------------- -ensure_application_loaded() -> - %% We end up looking at the rabbit app's env for HiPE and log - %% handling, so it needs to be loaded. But during the tests, it - %% may end up getting loaded twice, so guard against that. - case application:load(rabbit) of - ok -> ok; - {error, {already_loaded, rabbit}} -> ok - end. - -spec start() -> 'ok'. start() -> - start_it(fun() -> - %% We do not want to upgrade mnesia after just - %% restarting the app. - ok = ensure_application_loaded(), - HipeResult = rabbit_hipe:maybe_hipe_compile(), - ok = start_logger(), - rabbit_hipe:log_hipe_result(HipeResult), - Apps = load_all_apps(), - rabbit_feature_flags:initialize_registry(), - rabbit_node_monitor:prepare_cluster_status_files(), - rabbit_mnesia:check_cluster_consistency(), - broker_start(Apps) - end). + %% start() vs. boot(): we want to throw an error in start(). + start_it(temporary). -spec boot() -> 'ok'. boot() -> - start_it(fun() -> - ensure_config(), - ok = ensure_application_loaded(), - HipeResult = rabbit_hipe:maybe_hipe_compile(), - ok = start_logger(), - rabbit_hipe:log_hipe_result(HipeResult), - Apps = load_all_apps(), - rabbit_feature_flags:initialize_registry(), - rabbit_node_monitor:prepare_cluster_status_files(), - ok = rabbit_upgrade:maybe_upgrade_mnesia(), - %% It's important that the consistency check happens after - %% the upgrade, since if we are a secondary node the - %% primary node will have forgotten us - rabbit_mnesia:check_cluster_consistency(), - broker_start(Apps) - end). - -ensure_config() -> - case rabbit_config:validate_config_files() of - ok -> ok; - {error, {ErrFmt, ErrArgs}} -> - throw({error, {check_config_file, ErrFmt, ErrArgs}}) + %% start() vs. boot(): we want the node to exit in boot(). Because + %% applications are started with `transient`, any error during their + %% startup will abort the node. + start_it(transient). + +run_prelaunch_second_phase() -> + %% Finish the prelaunch phase started by the `rabbitmq_prelaunch` + %% application. + %% + %% The first phase was handled by the `rabbitmq_prelaunch` + %% application. It was started in one of the following way: + %% - from an Erlang release boot script; + %% - from the rabbit:boot/0 or rabbit:start/0 functions. + %% + %% The `rabbitmq_prelaunch` application creates the context map from + %% the environment and the configuration files early during Erlang + %% VM startup. Once it is done, all application environments are + %% configured (in particular `mnesia` and `ra`). + %% + %% This second phase depends on other modules & facilities of + %% RabbitMQ core. That's why we need to run it now, from the + %% `rabbit` application start function. + + %% We assert Mnesia is stopped before we run the prelaunch + %% phases. See `rabbit_prelaunch` for an explanation. + %% + %% This is the second assertion, just in case Mnesia is started + %% between the two prelaunch phases. + rabbit_prelaunch:assert_mnesia_is_stopped(), + + %% Get the context created by `rabbitmq_prelaunch` then proceed + %% with all steps in this phase. + #{initial_pass := IsInitialPass} = + Context = rabbit_prelaunch:get_context(), + + case IsInitialPass of + true -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug( + "== Prelaunch phase [2/2] (initial pass) =="); + false -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Prelaunch phase [2/2] =="), + ok + end, + + %% 1. Feature flags registry. + ok = rabbit_prelaunch_feature_flags:setup(Context), + + %% 2. Configuration check + loading. + ok = rabbit_prelaunch_conf:setup(Context), + + %% 3. Logging. + ok = rabbit_prelaunch_logging:setup(Context), + + case IsInitialPass of + true -> + %% 4. HiPE compilation. + ok = rabbit_prelaunch_hipe:setup(Context); + false -> + ok end, - case rabbit_config:prepare_and_use_config() of - {error, {generation_error, Error}} -> - throw({error, {generate_config_file, Error}}); - ok -> ok - end. -load_all_apps() -> - Plugins = rabbit_plugins:setup(), - ToBeLoaded = Plugins ++ ?APPS, - app_utils:load_applications(ToBeLoaded), - ToBeLoaded. + %% 5. Clustering. + ok = rabbit_prelaunch_cluster:setup(Context), -broker_start(Apps) -> - start_loaded_apps(Apps), - maybe_sd_notify(), - ok = rabbit_lager:broker_is_started(), - ok = log_broker_started(rabbit_plugins:strictly_plugins(rabbit_plugins:active())). + %% Start Mnesia now that everything is ready. + rabbit_log_prelaunch:debug("Starting Mnesia"), + ok = mnesia:start(), + + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Prelaunch DONE =="), + + case IsInitialPass of + true -> rabbit_prelaunch:initial_pass_finished(); + false -> ok + end, + ok. %% Try to send systemd ready notification if it makes sense in the %% current environment. standard_error is used intentionally in all @@ -465,41 +477,89 @@ sd_wait_activation(Port, Unit, AttemptsLeft) -> false end. -start_it(StartFun) -> +start_it(StartType) -> + case spawn_boot_marker() of + {ok, Marker} -> + T0 = erlang:timestamp(), + rabbit_log:info("RabbitMQ is asked to start...", []), + try + {ok, _} = application:ensure_all_started(rabbitmq_prelaunch, + StartType), + {ok, _} = application:ensure_all_started(rabbit, + StartType), + ok = wait_for_ready_or_stopped(), + + T1 = erlang:timestamp(), + rabbit_log_prelaunch:debug( + "Time to start RabbitMQ: ~p µs", + [timer:now_diff(T1, T0)]), + stop_boot_marker(Marker), + ok + catch + error:{badmatch, Error}:_ -> + stop_boot_marker(Marker), + case StartType of + temporary -> throw(Error); + _ -> exit(Error) + end + end; + {already_booting, Marker} -> + stop_boot_marker(Marker), + ok + end. + +wait_for_ready_or_stopped() -> + ok = rabbit_prelaunch:wait_for_boot_state(ready), + case rabbit_prelaunch:get_boot_state() of + ready -> + ok; + _ -> + ok = rabbit_prelaunch:wait_for_boot_state(stopped), + rabbit_prelaunch:get_stop_reason() + end. + +spawn_boot_marker() -> + %% Compatibility with older RabbitMQ versions: + %% We register a process doing nothing to indicate that RabbitMQ is + %% booting. This is checked by `is_booting(Node)` on a remote node. Marker = spawn_link(fun() -> receive stop -> ok end end), case catch register(rabbit_boot, Marker) of - true -> try - case is_running() of - true -> ok; - false -> StartFun() - end - catch Class:Reason -> - boot_error(Class, Reason) - after - unlink(Marker), - Marker ! stop, - %% give the error loggers some time to catch up - timer:sleep(100) - end; - _ -> unlink(Marker), - Marker ! stop + true -> {ok, Marker}; + _ -> {already_booting, Marker} end. +stop_boot_marker(Marker) -> + unlink(Marker), + Marker ! stop, + ok. + -spec stop() -> 'ok'. stop() -> - case whereis(rabbit_boot) of - undefined -> ok; - _ -> - rabbit_log:info("RabbitMQ hasn't finished starting yet. Waiting for startup to finish before stopping..."), - ok = wait_for_boot_to_finish(node()) - end, - rabbit_log:info("RabbitMQ is asked to stop...~n", []), - Apps = ?APPS ++ rabbit_plugins:active(), + case wait_for_ready_or_stopped() of + ok -> + case rabbit_prelaunch:get_boot_state() of + ready -> + rabbit_log:info("RabbitMQ is asked to stop..."), + do_stop(), + rabbit_log:info( + "Successfully stopped RabbitMQ and its dependencies"), + ok; + stopped -> + ok + end; + _ -> + ok + end. + +do_stop() -> + Apps0 = ?APPS ++ rabbit_plugins:active(), + %% We ensure that Mnesia is stopped last (or more exactly, after rabbit). + Apps1 = app_utils:app_dependency_order(Apps0, true) -- [mnesia], + Apps = [mnesia | Apps1], %% this will also perform unregistration with the peer discovery backend %% as needed - stop_apps(app_utils:app_dependency_order(Apps, true)), - rabbit_log:info("Successfully stopped RabbitMQ and its dependencies~n", []). + stop_apps(Apps). -spec stop_and_halt() -> no_return(). @@ -541,57 +601,8 @@ start_apps(Apps, RestartTypes) -> ok = rabbit_feature_flags:refresh_feature_flags_after_app_load(Apps), start_loaded_apps(Apps, RestartTypes). -start_loaded_apps(Apps) -> - start_loaded_apps(Apps, #{}). - start_loaded_apps(Apps, RestartTypes) -> - ensure_sysmon_handler_app_config(), - %% make Ra use a custom logger that dispatches to lager instead of the - %% default OTP logger - application:set_env(ra, logger_module, rabbit_log_ra_shim), - %% use a larger segments size for queues - case application:get_env(ra, segment_max_entries) of - undefined -> - application:set_env(ra, segment_max_entries, 32768); - _ -> - ok - end, - case application:get_env(ra, wal_max_size_bytes) of - undefined -> - application:set_env(ra, wal_max_size_bytes, 536870912); %% 5 * 2 ^ 20 - _ -> - ok - end, - ConfigEntryDecoder = case application:get_env(rabbit, config_entry_decoder) of - undefined -> - []; - {ok, Val} -> - Val - end, - PassPhrase = case proplists:get_value(passphrase, ConfigEntryDecoder) of - prompt -> - IoDevice = get_input_iodevice(), - io:setopts(IoDevice, [{echo, false}]), - PP = lists:droplast(io:get_line(IoDevice, - "\nPlease enter the passphrase to unlock encrypted " - "configuration entries.\n\nPassphrase: ")), - io:setopts(IoDevice, [{echo, true}]), - io:format(IoDevice, "~n", []), - PP; - {file, Filename} -> - {ok, File} = file:read_file(Filename), - [PP|_] = binary:split(File, [<<"\r\n">>, <<"\n">>]), - PP; - PP -> - PP - end, - Algo = { - proplists:get_value(cipher, ConfigEntryDecoder, rabbit_pbe:default_cipher()), - proplists:get_value(hash, ConfigEntryDecoder, rabbit_pbe:default_hash()), - proplists:get_value(iterations, ConfigEntryDecoder, rabbit_pbe:default_iterations()), - PassPhrase - }, - decrypt_config(Apps, Algo), + rabbit_prelaunch_conf:decrypt_config(Apps), OrderedApps = app_utils:app_dependency_order(Apps, false), case lists:member(rabbit, Apps) of false -> rabbit_boot_steps:run_boot_steps(Apps); %% plugin activation @@ -601,102 +612,6 @@ start_loaded_apps(Apps, RestartTypes) -> handle_app_error(could_not_start), RestartTypes). -%% rabbitmq/rabbitmq-server#952 -%% This function is to be called after configuration has been optionally generated -%% and the sysmon_handler application loaded, but not started. It will ensure that -%% sane defaults are used for configuration settings that haven't been set by the -%% user -ensure_sysmon_handler_app_config() -> - Defaults = [ - {process_limit, 100}, - {port_limit, 100}, - {gc_ms_limit, 0}, - {schedule_ms_limit, 0}, - {heap_word_limit, 0}, - {busy_port, false}, - {busy_dist_port, true} - ], - lists:foreach(fun({K, V}) -> - case application:get_env(sysmon_handler, K) of - undefined -> - application:set_env(sysmon_handler, K, V); - _ -> - ok - end - end, Defaults). - -%% This function retrieves the correct IoDevice for requesting -%% input. The problem with using the default IoDevice is that -%% the Erlang shell prevents us from getting the input. -%% -%% Instead we therefore look for the io process used by the -%% shell and if it can't be found (because the shell is not -%% started e.g with -noshell) we use the 'user' process. -%% -%% This function will not work when either -oldshell or -noinput -%% options are passed to erl. -get_input_iodevice() -> - case whereis(user) of - undefined -> user; - User -> - case group:interfaces(User) of - [] -> - user; - [{user_drv, Drv}] -> - case user_drv:interfaces(Drv) of - [] -> - user; - [{current_group, IoDevice}] -> - IoDevice - end - end - end. - -decrypt_config([], _) -> - ok; -decrypt_config([App|Apps], Algo) -> - decrypt_app(App, application:get_all_env(App), Algo), - decrypt_config(Apps, Algo). - -decrypt_app(_, [], _) -> - ok; -decrypt_app(App, [{Key, Value}|Tail], Algo) -> - try begin - case decrypt(Value, Algo) of - Value -> - ok; - NewValue -> - application:set_env(App, Key, NewValue) - end - end - catch - exit:{bad_configuration, config_entry_decoder} -> - exit({bad_configuration, config_entry_decoder}); - _:Msg -> - rabbit_log:info("Error while decrypting key '~p'. Please check encrypted value, passphrase, and encryption configuration~n", [Key]), - exit({decryption_error, {key, Key}, Msg}) - end, - decrypt_app(App, Tail, Algo). - -decrypt({encrypted, _}, {_, _, _, undefined}) -> - exit({bad_configuration, config_entry_decoder}); -decrypt({encrypted, EncValue}, {Cipher, Hash, Iterations, Password}) -> - rabbit_pbe:decrypt_term(Cipher, Hash, Iterations, Password, EncValue); -decrypt(List, Algo) when is_list(List) -> - decrypt_list(List, Algo, []); -decrypt(Value, _) -> - Value. - -%% We make no distinction between strings and other lists. -%% When we receive a string, we loop through each element -%% and ultimately return the string unmodified, as intended. -decrypt_list([], _, Acc) -> - lists:reverse(Acc); -decrypt_list([{Key, Value}|Tail], Algo, Acc) when Key =/= encrypted -> - decrypt_list(Tail, Algo, [{Key, decrypt(Value, Algo)}|Acc]); -decrypt_list([Value|Tail], Algo, Acc) -> - decrypt_list(Tail, Algo, [decrypt(Value, Algo)|Acc]). - -spec stop_apps([app_name()]) -> 'ok'. stop_apps([]) -> @@ -725,11 +640,15 @@ handle_app_error(Term) -> is_booting() -> is_booting(node()). +is_booting(Node) when Node =:= node() -> + case rabbit_prelaunch:get_boot_state() of + booting -> true; + _ -> false + end; is_booting(Node) -> - case rpc:call(Node, erlang, whereis, [rabbit_boot]) of + case rpc:call(Node, rabbit, is_booting, []) of {badrpc, _} = Err -> Err; - undefined -> false; - P when is_pid(P) -> true + Ret -> Ret end. @@ -795,9 +714,6 @@ do_wait_for_boot_to_start(Node, IterationsLeft) -> ok end. -wait_for_boot_to_finish(Node) -> - wait_for_boot_to_finish(Node, false, ?BOOT_FINISH_TIMEOUT). - wait_for_boot_to_finish(Node, PrintProgressReports) -> wait_for_boot_to_finish(Node, PrintProgressReports, ?BOOT_FINISH_TIMEOUT). @@ -917,17 +833,22 @@ total_queue_count() -> end, 0, rabbit_vhost:list_names()). -%% TODO this only determines if the rabbit application has started, -%% not if it is running, never mind plugins. It would be nice to have -%% more nuance here. - -spec is_running() -> boolean(). is_running() -> is_running(node()). -spec is_running(node()) -> boolean(). -is_running(Node) -> rabbit_nodes:is_process_running(Node, rabbit). +is_running(Node) when Node =:= node() -> + case rabbit_prelaunch:get_boot_state() of + ready -> true; + _ -> false + end; +is_running(Node) -> + case rpc:call(Node, rabbit, is_running, []) of + true -> true; + _ -> false + end. is_booted() -> is_booted(node()). @@ -983,105 +904,136 @@ rotate_logs() -> {'ok',pid()}. start(normal, []) -> - case erts_version_check() of - ok -> - rabbit_log:info("~n Starting RabbitMQ ~s on Erlang ~s~n ~s~n ~s~n", - [rabbit_misc:version(), rabbit_misc:otp_release(), - ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]), - {ok, SupPid} = rabbit_sup:start_link(), - true = register(rabbit, self()), - print_banner(), - log_banner(), - warn_if_kernel_config_dubious(), - warn_if_disc_io_options_dubious(), - rabbit_boot_steps:run_boot_steps(), - {ok, SupPid}; - {error, {erlang_version_too_old, - {found, OTPRel, ERTSVer}, - {required, ?OTP_MINIMUM, ?ERTS_MINIMUM}}} -> - Msg = "This RabbitMQ version cannot run on Erlang ~s (erts ~s): " - "minimum required version is ~s (erts ~s)", - Args = [OTPRel, ERTSVer, ?OTP_MINIMUM, ?ERTS_MINIMUM], - rabbit_log:error(Msg, Args), - %% also print to stderr to make this more visible - io:format(standard_error, "Error: " ++ Msg ++ "~n", Args), - {error, {erlang_version_too_old, rabbit_misc:format("Erlang ~s or later is required, started on ~s", [?OTP_MINIMUM, OTPRel])}}; - Error -> + %% Reset boot state and clear the stop reason again (it was already + %% made in rabbitmq_prelaunch). + %% + %% This is important if the previous startup attempt failed after + %% rabbitmq_prelaunch was started and the application is still + %% running. + rabbit_prelaunch:set_boot_state(booting), + rabbit_prelaunch:clear_stop_reason(), + + try + run_prelaunch_second_phase(), + + rabbit_log:info("~n Starting RabbitMQ ~s on Erlang ~s~n ~s~n ~s~n", + [rabbit_misc:version(), rabbit_misc:otp_release(), + ?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]), + {ok, SupPid} = rabbit_sup:start_link(), + + %% Compatibility with older RabbitMQ versions + required by + %% rabbit_node_monitor:notify_node_up/0: + %% + %% We register the app process under the name `rabbit`. This is + %% checked by `is_running(Node)` on a remote node. The process + %% is also monitord by rabbit_node_monitor. + %% + %% The process name must be registered *before* running the boot + %% steps: that's when rabbit_node_monitor will set the process + %% monitor up. + %% + %% Note that plugins were not taken care of at this point + %% either. + rabbit_log_prelaunch:debug( + "Register `rabbit` process (~p) for rabbit_node_monitor", + [self()]), + true = register(rabbit, self()), + + print_banner(), + log_banner(), + warn_if_kernel_config_dubious(), + warn_if_disc_io_options_dubious(), + %% We run `rabbit` boot steps only for now. Plugins boot steps + %% will be executed as part of the postlaunch phase after they + %% are started. + rabbit_boot_steps:run_boot_steps([rabbit]), + run_postlaunch_phase(), + {ok, SupPid} + catch + throw:{error, _} = Error -> + mnesia:stop(), + rabbit_prelaunch_errors:log_error(Error), + rabbit_prelaunch:set_stop_reason(Error), + rabbit_prelaunch:set_boot_state(stopped), + Error; + Class:Exception:Stacktrace -> + mnesia:stop(), + rabbit_prelaunch_errors:log_exception( + Class, Exception, Stacktrace), + Error = {error, Exception}, + rabbit_prelaunch:set_stop_reason(Error), + rabbit_prelaunch:set_boot_state(stopped), Error end. +run_postlaunch_phase() -> + spawn(fun() -> do_run_postlaunch_phase() end). + +do_run_postlaunch_phase() -> + %% Once RabbitMQ itself is started, we need to run a few more steps, + %% in particular start plugins. + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Postlaunch phase =="), + + try + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Plugins =="), + + rabbit_log_prelaunch:debug("Setting plugins up"), + Plugins = rabbit_plugins:setup(), + rabbit_log_prelaunch:debug( + "Starting the following plugins: ~p", [Plugins]), + app_utils:load_applications(Plugins), + ok = rabbit_feature_flags:refresh_feature_flags_after_app_load( + Plugins), + lists:foreach( + fun(Plugin) -> + case application:ensure_all_started(Plugin) of + {ok, _} -> rabbit_boot_steps:run_boot_steps([Plugin]); + Error -> throw(Error) + end + end, Plugins), + + maybe_sd_notify(), + + rabbit_log_prelaunch:debug("Marking RabbitMQ as running"), + rabbit_prelaunch:set_boot_state(ready), + ok = rabbit_lager:broker_is_started(), + ok = log_broker_started( + rabbit_plugins:strictly_plugins(rabbit_plugins:active())) + catch + throw:{error, _} = Error -> + rabbit_prelaunch_errors:log_error(Error), + rabbit_prelaunch:set_stop_reason(Error), + do_stop(); + Class:Exception:Stacktrace -> + rabbit_prelaunch_errors:log_exception( + Class, Exception, Stacktrace), + Error = {error, Exception}, + rabbit_prelaunch:set_stop_reason(Error), + do_stop() + end. + prep_stop(State) -> rabbit_peer_discovery:maybe_unregister(), State. -spec stop(_) -> 'ok'. -stop(_State) -> +stop(State) -> + rabbit_prelaunch:set_boot_state(stopping), ok = rabbit_alarm:stop(), ok = case rabbit_mnesia:is_clustered() of true -> ok; false -> rabbit_table:clear_ram_only_tables() end, + case State of + [] -> rabbit_prelaunch:set_stop_reason(normal); + _ -> rabbit_prelaunch:set_stop_reason(State) + end, + rabbit_prelaunch:set_boot_state(stopped), ok. --spec boot_error(term(), not_available | [tuple()]) -> no_return(). - -boot_error(_, {could_not_start, rabbit, {{timeout_waiting_for_tables, _}, _}}) -> - AllNodes = rabbit_mnesia:cluster_nodes(all), - Suffix = "~nBACKGROUND~n==========~n~n" - "This cluster node was shut down while other nodes were still running.~n" - "To avoid losing data, you should start the other nodes first, then~n" - "start this one. To force this node to start, first invoke~n" - "\"rabbitmqctl force_boot\". If you do so, any changes made on other~n" - "cluster nodes after this one was shut down may be lost.~n", - {Err, Nodes} = - case AllNodes -- [node()] of - [] -> {"Timeout contacting cluster nodes. Since RabbitMQ was" - " shut down forcefully~nit cannot determine which nodes" - " are timing out.~n" ++ Suffix, []}; - Ns -> {rabbit_misc:format( - "Timeout contacting cluster nodes: ~p.~n" ++ Suffix, [Ns]), - Ns} - end, - log_boot_error_and_exit( - timeout_waiting_for_tables, - "~n" ++ Err ++ rabbit_nodes:diagnostics(Nodes), []); -boot_error(_, {error, {cannot_log_to_file, unknown, Reason}}) -> - log_boot_error_and_exit(could_not_initialise_logger, - "failed to initialised logger: ~p~n", - [Reason]); -boot_error(_, {error, {cannot_log_to_file, LogFile, - {cannot_create_parent_dirs, _, Reason}}}) -> - log_boot_error_and_exit(could_not_initialise_logger, - "failed to create parent directory for log file at '~s', reason: ~p~n", - [LogFile, Reason]); -boot_error(_, {error, {cannot_log_to_file, LogFile, Reason}}) -> - log_boot_error_and_exit(could_not_initialise_logger, - "failed to open log file at '~s', reason: ~p~n", - [LogFile, Reason]); -boot_error(_, {error, {generate_config_file, Error}}) -> - log_boot_error_and_exit(generate_config_file, - "~nConfig file generation failed:~n~s" - "In case the setting comes from a plugin, make sure that the plugin is enabled.~n" - "Alternatively remove the setting from the config.~n", - [Error]); -boot_error(Class, Reason) -> - LogLocations = log_locations(), - log_boot_error_and_exit( - Reason, - "~nError description:~s" - "~nLog file(s) (may contain more information):~n" ++ - lists:flatten([" ~s~n" || _ <- lists:seq(1, length(LogLocations))]), - [lager:pr_stacktrace(erlang:get_stacktrace(), {Class, Reason})] ++ - LogLocations). - --spec log_boot_error_and_exit(_, _, _) -> no_return(). -log_boot_error_and_exit(Reason, Format, Args) -> - rabbit_log:error(Format, Args), - io:format(standard_error, "~nBOOT FAILED~n===========~n" ++ Format ++ "~n", Args), - timer:sleep(1000), - exit(Reason). - %%--------------------------------------------------------------------------- %% boot step functions @@ -1141,10 +1093,6 @@ insert_default_data() -> %%--------------------------------------------------------------------------- %% logging -start_logger() -> - rabbit_lager:start_logger(), - ok. - -spec log_locations() -> [rabbit_lager:log_location()]. log_locations() -> rabbit_lager:log_locations(). @@ -1176,25 +1124,29 @@ log_broker_started(Plugins) -> rabbit_log:info(Message), io:format(" completed with ~p plugins.~n", [length(Plugins)]). -erts_version_check() -> - ERTSVer = erlang:system_info(version), - OTPRel = rabbit_misc:otp_release(), - case rabbit_misc:version_compare(?ERTS_MINIMUM, ERTSVer, lte) of - true when ?ERTS_MINIMUM =/= ERTSVer -> - ok; - true when ?ERTS_MINIMUM =:= ERTSVer andalso ?OTP_MINIMUM =< OTPRel -> - %% When a critical regression or bug is found, a new OTP - %% release can be published without changing the ERTS - %% version. For instance, this is the case with R16B03 and - %% R16B03-1. - %% - %% In this case, we compare the release versions - %% alphabetically. - ok; - _ -> {error, {erlang_version_too_old, - {found, OTPRel, ERTSVer}, - {required, ?OTP_MINIMUM, ?ERTS_MINIMUM}}} - end. +-define(RABBIT_TEXT_LOGO, + "~n ## ## ~s ~s" + "~n ## ##" + "~n ########## ~s" + "~n ###### ##" + "~n ########## ~s"). +-define(FG8_START, "\033[38;5;202m"). +-define(BG8_START, "\033[48;5;202m"). +-define(FG32_START, "\033[38;2;255;102;0m"). +-define(BG32_START, "\033[48;2;255;102;0m"). +-define(C_END, "\033[0m"). +-define(RABBIT_8BITCOLOR_LOGO, + "~n " ?BG8_START " " ?C_END " " ?BG8_START " " ?C_END " \033[1m" ?FG8_START "~s" ?C_END " ~s" + "~n " ?BG8_START " " ?C_END " " ?BG8_START " " ?C_END + "~n " ?BG8_START " " ?C_END " ~s" + "~n " ?BG8_START " " ?C_END " " ?BG8_START " " ?C_END + "~n " ?BG8_START " " ?C_END " ~s"). +-define(RABBIT_32BITCOLOR_LOGO, + "~n " ?BG32_START " " ?C_END " " ?BG32_START " " ?C_END " \033[1m" ?FG32_START "~s" ?C_END " ~s" + "~n " ?BG32_START " " ?C_END " " ?BG32_START " " ?C_END + "~n " ?BG32_START " " ?C_END " ~s" + "~n " ?BG32_START " " ?C_END " " ?BG32_START " " ?C_END + "~n " ?BG32_START " " ?C_END " ~s"). print_banner() -> {ok, Product} = application:get_key(description), @@ -1205,14 +1157,23 @@ print_banner() -> (_, []) -> {"", ["(none)"]} end, + Logo = case rabbit_prelaunch:get_context() of + %% We use the colored logo only when running the + %% interactive shell and when colors are supported. + %% + %% Basically it means it will be used on Unix when + %% running "make run-broker" and that's about it. + #{os_type := {unix, darwin}, + interactive_shell := true, + output_supports_colors := true} -> ?RABBIT_8BITCOLOR_LOGO; + #{interactive_shell := true, + output_supports_colors := true} -> ?RABBIT_32BITCOLOR_LOGO; + _ -> ?RABBIT_TEXT_LOGO + end, %% padded list lines {LogFmt, LogLocations} = LineListFormatter("~n ~ts", log_locations()), {CfgFmt, CfgLocations} = LineListFormatter("~n ~ts", config_locations()), - io:format("~n ## ## ~s ~s" - "~n ## ##" - "~n ########## ~s" - "~n ###### ##" - "~n ########## ~s" + io:format(Logo ++ "~n" "~n Doc guides: https://rabbitmq.com/documentation.html" "~n Support: https://rabbitmq.com/contact.html" diff --git a/src/rabbit_config.erl b/src/rabbit_config.erl index 6a2cc5c663..573a972c68 100644 --- a/src/rabbit_config.erl +++ b/src/rabbit_config.erl @@ -1,164 +1,33 @@ -module(rabbit_config). -export([ - generate_config_file/5, - prepare_and_use_config/0, - prepare_config/1, - update_app_config/1, schema_dir/0, config_files/0, - get_advanced_config/0, - validate_config_files/0 + get_advanced_config/0 ]). -export_type([config_location/0]). -type config_location() :: string(). -prepare_and_use_config() -> - case legacy_erlang_term_config_used() of - true -> - %% Use .config file - ok; - false -> - case prepare_config(get_confs()) of - ok -> - %% No .conf to generate from - ok; - {ok, GeneratedConfigFile} -> - %% Generated config file - update_app_config(GeneratedConfigFile); - {error, Err} -> - {error, Err} - end - end. - %% we support both the classic Erlang term %% config file (rabbitmq.config) as well as rabbitmq.conf legacy_erlang_term_config_used() -> - case init:get_argument(config) of - error -> false; - {ok, [Config | _]} -> - ConfigFile = Config ++ ".config", - rabbit_file:is_file(ConfigFile) - andalso - get_advanced_config() == none + case get_prelaunch_config_state() of + #{config_type := erlang, + config_advanced_file := undefined} -> + true; + _ -> + false end. get_confs() -> - case init:get_argument(conf) of - {ok, Confs} -> [ filename:rootname(Conf, ".conf") ++ ".conf" - || Conf <- Confs ]; - _ -> [] - end. - -prepare_config(Confs) -> - case {init:get_argument(conf_dir), init:get_argument(conf_script_dir)} of - {{ok, ConfDir}, {ok, ScriptDir}} -> - ConfFiles = [Conf || Conf <- Confs, - rabbit_file:is_file(Conf)], - case ConfFiles of - [] -> ok; - _ -> - case generate_config_file(ConfFiles, ConfDir, ScriptDir) of - {ok, GeneratedConfigFile} -> - {ok, GeneratedConfigFile}; - {error, Reason} -> - {error, Reason} - end - end; - _ -> ok - end. - -update_app_config(ConfigFile) -> - RunningApps = [ App || {App, _, _} <- application:which_applications() ], - LoadedApps = [ App || {App, _, _} <- application:loaded_applications() ], - {ok, [Config]} = file:consult(ConfigFile), - %% For application config to be updated, applications should - %% be unloaded first. - %% If an application is already running, print an error. - lists:foreach(fun({App, AppConfig}) -> - case lists:member(App, RunningApps) of - true -> - maybe_print_warning_for_running_app(App, AppConfig); - false -> - case lists:member(App, LoadedApps) of - true -> application:unload(App); - false -> ok - end - end - end, - Config), - maybe_set_net_ticktime(proplists:get_value(kernel, Config)), - ok = application_controller:change_application_data([], [ConfigFile]), - %% Make sure to load all the applications we're unloaded - lists:foreach(fun(App) -> application:load(App) end, LoadedApps), - ok. - -maybe_print_warning_for_running_app(kernel, Config) -> - ConfigWithoutSupportedEntry = proplists:delete(net_ticktime, Config), - case length(ConfigWithoutSupportedEntry) > 0 of - true -> io:format(standard_error, - "~nUnable to update config for app ~p from a .conf file." - " The app is already running. Use advanced.config instead.~n", [kernel]); - false -> ok - end; -maybe_print_warning_for_running_app(App, _Config) -> - io:format(standard_error, - "~nUnable to update config for app ~p from a .conf file: " - " The app is already running.~n", - [App]). - -maybe_set_net_ticktime(undefined) -> - ok; -maybe_set_net_ticktime(KernelConfig) -> - case proplists:get_value(net_ticktime, KernelConfig) of - undefined -> - ok; - NetTickTime -> - case net_kernel:set_net_ticktime(NetTickTime, 0) of - unchanged -> - ok; - change_initiated -> - ok; - {ongoing_change_to, NewNetTicktime} -> - io:format(standard_error, - "~nCouldn't set net_ticktime to ~p " - "as net_kernel is busy changing net_ticktime to ~p seconds ~n", - [NetTickTime, NewNetTicktime]) - end - end. - -generate_config_file(ConfFiles, ConfDir, ScriptDir) -> - generate_config_file(ConfFiles, ConfDir, ScriptDir, - schema_dir(), get_advanced_config()). - - -generate_config_file(ConfFiles, ConfDir, ScriptDir, SchemaDir, Advanced) -> - prepare_plugin_schemas(SchemaDir), - Cuttlefish = filename:join([ScriptDir, "cuttlefish"]), - GeneratedDir = filename:join([ConfDir, "generated"]), - - AdvancedConfigArg = case check_advanced_config(Advanced) of - {ok, FileName} -> [" -a ", FileName]; - none -> [] - end, - rabbit_file:recursive_delete([GeneratedDir]), - Command = lists:concat(["escript ", "\"", Cuttlefish, "\"", - " -f rabbitmq -s ", "\"", SchemaDir, "\"", - " -e ", "\"", ConfDir, "\"", - [[" -c \"", ConfFile, "\""] || ConfFile <- ConfFiles], - AdvancedConfigArg]), - rabbit_log:debug("Generating config file using '~s'", [Command]), - Result = rabbit_misc:os_cmd(Command), - case string:str(Result, " -config ") of - 0 -> {error, {generation_error, Result}}; + case get_prelaunch_config_state() of + #{config_files := Confs} -> + [ filename:rootname(Conf, ".conf") ++ ".conf" + || Conf <- Confs ]; _ -> - [OutFile] = rabbit_file:wildcard("rabbitmq.*.config", GeneratedDir), - ResultFile = filename:join([GeneratedDir, "rabbitmq.config"]), - rabbit_file:rename(filename:join([GeneratedDir, OutFile]), - ResultFile), - {ok, ResultFile} + [] end. schema_dir() -> @@ -171,17 +40,10 @@ schema_dir() -> end end. -check_advanced_config(none) -> none; -check_advanced_config(ConfigName) -> - case rabbit_file:is_file(ConfigName) of - true -> {ok, ConfigName}; - false -> none - end. - get_advanced_config() -> - case init:get_argument(conf_advanced) of + case get_prelaunch_config_state() of %% There can be only one advanced.config - {ok, [FileName | _]} -> + #{config_advanced_file := FileName} -> case rabbit_file:is_file(FileName) of true -> FileName; false -> none @@ -189,26 +51,21 @@ get_advanced_config() -> _ -> none end. - -prepare_plugin_schemas(SchemaDir) -> - case rabbit_file:is_dir(SchemaDir) of - true -> rabbit_plugins:extract_schemas(SchemaDir); - false -> ok - end. - -spec config_files() -> [config_location()]. config_files() -> case legacy_erlang_term_config_used() of true -> - case init:get_argument(config) of - {ok, Files} -> [ filename:absname(filename:rootname(File) ++ ".config") - || [File] <- Files]; - error -> case config_setting() of - none -> []; - File -> [filename:absname(filename:rootname(File, ".config") ++ ".config") - ++ - " (not found)"] - end + case get_prelaunch_config_state() of + #{config_files := Files} -> + [ filename:absname(filename:rootname(File) ++ ".config") + || File <- Files]; + _ -> + case config_setting() of + none -> []; + File -> [filename:absname(filename:rootname(File, ".config") ++ ".config") + ++ + " (not found)"] + end end; false -> ConfFiles = [filename:absname(File) || File <- get_confs(), @@ -221,6 +78,8 @@ config_files() -> end. +get_prelaunch_config_state() -> + rabbit_prelaunch_conf:get_config_state(). %% This is a pain. We want to know where the config file is. But we %% can't specify it on the command line if it is missing or the VM @@ -232,95 +91,9 @@ config_files() -> config_setting() -> case application:get_env(rabbit, windows_service_config) of {ok, File1} -> File1; - undefined -> case os:getenv("RABBITMQ_CONFIG_FILE") of - false -> none; - File2 -> File2 - end - end. - --spec validate_config_files() -> ok | {error, {Fmt :: string(), Args :: list()}}. -validate_config_files() -> - ConfigFile = os:getenv("RABBITMQ_CONFIG_FILE"), - AdvancedConfigFile = get_advanced_config(), - AssertConfig = case filename:extension(ConfigFile) of - ".config" -> assert_config(ConfigFile, "RABBITMQ_CONFIG_FILE"); - ".conf" -> assert_conf(ConfigFile, "RABBITMQ_CONFIG_FILE"); - _ -> ok - end, - case AssertConfig of - ok -> - assert_config(AdvancedConfigFile, "RABBITMQ_ADVANCED_CONFIG_FILE"); - {error, Err} -> - {error, Err} + undefined -> + case application:get_env(rabbitmq_prelaunch, context) of + #{main_config_file := File2} -> File2; + _ -> none + end end. - -assert_config("", _) -> ok; -assert_config(none, _) -> ok; -assert_config(Filename, Env) -> - assert_config(filename:extension(Filename), Filename, Env). - --define(ERRMSG_INDENT, " "). - -assert_config(".config", Filename, Env) -> - case filelib:is_regular(Filename) of - true -> - case file:consult(Filename) of - {ok, []} -> {error, - {"Config file ~s should not be empty: ~s", - [Env, Filename]}}; - {ok, [_]} -> ok; - {ok, [_|_]} -> {error, - {"Config file ~s must contain ONE list ended by <dot>: ~s", - [Env, Filename]}}; - {error, {1, erl_parse, Err}} -> - % Note: the sequence of spaces is to indent from the [error] prefix, like this: - % - % 2018-09-06 07:05:40.225 [error] Unable to parse erlang terms from RABBITMQ_ADVANCED_CONFIG_FILE... - % Reason: ["syntax error before: ",[]] - {error, {"Unable to parse erlang terms from ~s file: ~s~n" - ?ERRMSG_INDENT - "Reason: ~p~n" - ?ERRMSG_INDENT - "Check that the file is in erlang term format. " ++ - case Env of - "RABBITMQ_CONFIG_FILE" -> - "If you are using the new ini-style format, the file extension should be '.conf'~n"; - _ -> "" - end, - [Env, Filename, Err]}}; - {error, Err} -> - {error, {"Unable to parse erlang terms from ~s file: ~s~n" - ?ERRMSG_INDENT - "Error: ~p~n", - [Env, Filename, Err]}} - end; - false -> - ok - end; -assert_config(BadExt, Filename, Env) -> - {error, {"'~s': Expected extension '.config', got extension '~s' for file '~s'~n", [Env, BadExt, Filename]}}. - -assert_conf("", _) -> ok; -assert_conf(Filename, Env) -> - assert_conf(filename:extension(Filename), Filename, Env). - -assert_conf(".conf", Filename, Env) -> - case filelib:is_regular(Filename) of - true -> - case file:consult(Filename) of - {ok, []} -> ok; - {ok, _} -> - {error, {"Wrong format of the config file ~s: ~s~n" - ?ERRMSG_INDENT - "Check that the file is in the new ini-style config format. " - "If you are using the old format the file extension should " - "be .config~n", - [Env, Filename]}}; - _ -> - ok - end; - false -> - ok - end; -assert_conf(BadExt, Filename, Env) -> - {error, {"'~s': Expected extension '.config', got extension '~s' for file '~s'~n", [Env, BadExt, Filename]}}. diff --git a/src/rabbit_hipe.erl b/src/rabbit_hipe.erl index bb13a3baf4..a180e2f1c9 100644 --- a/src/rabbit_hipe.erl +++ b/src/rabbit_hipe.erl @@ -20,17 +20,18 @@ maybe_hipe_compile() -> end. log_hipe_result({ok, disabled}) -> - ok; + rabbit_log_prelaunch:info( + "HiPE disabled: no modules were natively recompiled.~n", []); log_hipe_result({ok, already_compiled}) -> - rabbit_log:info( + rabbit_log_prelaunch:info( "HiPE in use: modules already natively compiled.~n", []); log_hipe_result({ok, Count, Duration}) -> - rabbit_log:info( + rabbit_log_prelaunch:info( "HiPE in use: compiled ~B modules in ~Bs.~n", [Count, Duration]); log_hipe_result(false) -> io:format( "~nNot HiPE compiling: HiPE not found in this Erlang installation.~n"), - rabbit_log:warning( + rabbit_log_prelaunch:warning( "Not HiPE compiling: HiPE not found in this Erlang installation.~n"). hipe_compile() -> diff --git a/src/rabbit_plugins.erl b/src/rabbit_plugins.erl index 7757b5229e..02e3e0d8de 100644 --- a/src/rabbit_plugins.erl +++ b/src/rabbit_plugins.erl @@ -20,10 +20,9 @@ -export([setup/0, active/0, read_enabled/1, list/1, list/2, dependencies/3, running_plugins/0]). -export([ensure/1]). --export([extract_schemas/1]). -export([validate_plugins/1, format_invalid_plugins/1]). -export([is_strictly_plugin/1, strictly_plugins/2, strictly_plugins/1]). --export([plugins_dir/0, plugins_expand_dir/0, enabled_plugins_file/0]). +-export([plugins_dir/0, plugin_names/1, plugins_expand_dir/0, enabled_plugins_file/0]). % Export for testing purpose. -export([is_version_supported/2, validate_plugins/2]). @@ -49,7 +48,6 @@ ensure1(FileJustChanged0) -> FileJustChanged -> Enabled = read_enabled(OurFile), Wanted = prepare_plugins(Enabled), - rabbit_config:prepare_and_use_config(), Current = active(), Start = Wanted -- Current, Stop = Current -- Wanted, @@ -132,50 +130,6 @@ setup() -> Enabled = enabled_plugins(), prepare_plugins(Enabled). -extract_schemas(SchemaDir) -> - application:load(rabbit), - {ok, EnabledFile} = application:get_env(rabbit, enabled_plugins_file), - Enabled = read_enabled(EnabledFile), - - {ok, PluginsDistDir} = application:get_env(rabbit, plugins_dir), - - AllPlugins = list(PluginsDistDir), - Wanted = dependencies(false, Enabled, AllPlugins), - WantedPlugins = lookup_plugins(Wanted, AllPlugins), - [ extract_schema(Plugin, SchemaDir) || Plugin <- WantedPlugins ], - application:unload(rabbit), - ok. - -extract_schema(#plugin{type = ez, location = Location}, SchemaDir) -> - {ok, Files} = zip:extract(Location, - [memory, {file_filter, - fun(#zip_file{name = Name}) -> - string:str(Name, "priv/schema") > 0 - end}]), - lists:foreach( - fun({FileName, Content}) -> - ok = file:write_file(filename:join([SchemaDir, - filename:basename(FileName)]), - Content) - end, - Files), - ok; -extract_schema(#plugin{type = dir, location = Location}, SchemaDir) -> - PluginSchema = filename:join([Location, - "priv", - "schema"]), - case rabbit_file:is_dir(PluginSchema) of - false -> ok; - true -> - PluginSchemaFiles = - [ filename:join(PluginSchema, FileName) - || FileName <- rabbit_file:wildcard(".*\\.schema", - PluginSchema) ], - [ file:copy(SchemaFile, SchemaDir) - || SchemaFile <- PluginSchemaFiles ] - end. - - %% @doc Lists the plugins which are currently running. -spec active() -> [plugin_name()]. diff --git a/src/rabbit_prelaunch.erl b/src/rabbit_prelaunch.erl deleted file mode 100644 index 51deb0f0ea..0000000000 --- a/src/rabbit_prelaunch.erl +++ /dev/null @@ -1,161 +0,0 @@ -%% 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 https://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-2019 Pivotal Software, Inc. All rights reserved. -%% - --module(rabbit_prelaunch). - --export([start/0, stop/0]). --export([config_file_check/0]). - --import(rabbit_misc, [pget/2, pget/3]). - --include("rabbit.hrl"). - --define(SET_DIST_PORT, 0). --define(ERROR_CODE, 1). --define(DO_NOT_SET_DIST_PORT, 2). --define(EX_USAGE, 64). - -%%---------------------------------------------------------------------------- - --spec start() -> no_return(). - -start() -> - case init:get_plain_arguments() of - [NodeStr] -> - Node = rabbit_nodes:make(NodeStr), - {NodeName, NodeHost} = rabbit_nodes:parts(Node), - ok = duplicate_node_check(NodeName, NodeHost), - ok = dist_port_set_check(), - ok = dist_port_range_check(), - ok = dist_port_use_check(NodeHost), - ok = config_file_check(); - [] -> - %% Ignore running node while installing windows service - ok = dist_port_set_check(), - ok - end, - rabbit_misc:quit(?SET_DIST_PORT), - ok. - --spec stop() -> 'ok'. - -stop() -> - ok. - -%%---------------------------------------------------------------------------- - -config_file_check() -> - case rabbit_config:validate_config_files() of - ok -> ok; - {error, {ErrFmt, ErrArgs}} -> - ErrMsg = io_lib:format(ErrFmt, ErrArgs), - {{Year, Month, Day}, {Hour, Minute, Second, Milli}} = lager_util:localtime_ms(), - io:format(standard_error, "~b-~2..0b-~2..0b ~2..0b:~2..0b:~2..0b.~b [error] ~s", - [Year, Month, Day, Hour, Minute, Second, Milli, ErrMsg]), - rabbit_misc:quit(?EX_USAGE) - end. - -%% Check whether a node with the same name is already running -duplicate_node_check(NodeName, NodeHost) -> - case rabbit_nodes:names(NodeHost) of - {ok, NamePorts} -> - case proplists:is_defined(NodeName, NamePorts) of - true -> io:format( - "ERROR: node with name ~p already running on ~p~n", - [NodeName, NodeHost]), - rabbit_misc:quit(?ERROR_CODE); - false -> ok - end; - {error, EpmdReason} -> - io:format("ERROR: epmd error for host ~s: ~s~n", - [NodeHost, rabbit_misc:format_inet_error(EpmdReason)]), - rabbit_misc:quit(?ERROR_CODE) - end. - -dist_port_set_check() -> - case get_config(os:getenv("RABBITMQ_CONFIG_ARG_FILE")) of - {ok, [Config]} -> - Kernel = pget(kernel, Config, []), - case {pget(inet_dist_listen_min, Kernel, none), - pget(inet_dist_listen_max, Kernel, none)} of - {none, none} -> ok; - _ -> rabbit_misc:quit(?DO_NOT_SET_DIST_PORT) - end; - {ok, _} -> - ok; - {error, _} -> - ok - end. - -get_config("") -> {error, nofile}; -get_config(File) -> - case consult_file(File) of - {ok, Contents} -> {ok, Contents}; - {error, _} = E -> E - end. - -consult_file(false) -> {error, nofile}; -consult_file(File) -> - FileName = case filename:extension(File) of - "" -> File ++ ".config"; - ".config" -> File; - _ -> "" - end, - file:consult(FileName). - -dist_port_range_check() -> - case os:getenv("RABBITMQ_DIST_PORT") of - false -> ok; - PortStr -> case catch list_to_integer(PortStr) of - Port when is_integer(Port) andalso Port > 65535 -> - rabbit_misc:quit(?DO_NOT_SET_DIST_PORT); - _ -> - ok - end - end. - -dist_port_use_check(NodeHost) -> - case os:getenv("RABBITMQ_DIST_PORT") of - false -> ok; - PortStr -> Port = list_to_integer(PortStr), - dist_port_use_check_ipv4(NodeHost, Port) - end. - -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:names(Host), - case [N || {N, P} <- Names, P =:= Port] of - [] -> io:format("ERROR: distribution port ~b in use on ~s " - "(by non-Erlang process?)~n", [Port, Host]); - [Name] -> io:format("ERROR: distribution port ~b in use by ~s@~s~n", - [Port, Name, Host]) - end, - rabbit_misc:quit(?ERROR_CODE). diff --git a/src/rabbit_prelaunch_cluster.erl b/src/rabbit_prelaunch_cluster.erl new file mode 100644 index 0000000000..9d3cda99e3 --- /dev/null +++ b/src/rabbit_prelaunch_cluster.erl @@ -0,0 +1,22 @@ +-module(rabbit_prelaunch_cluster). + +-export([setup/1]). + +setup(Context) -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Clustering =="), + rabbit_log_prelaunch:debug("Preparing cluster status files"), + rabbit_node_monitor:prepare_cluster_status_files(), + case Context of + #{initial_pass := true} -> + rabbit_log_prelaunch:debug("Upgrading Mnesia schema"), + ok = rabbit_upgrade:maybe_upgrade_mnesia(); + _ -> + ok + end, + %% It's important that the consistency check happens after + %% the upgrade, since if we are a secondary node the + %% primary node will have forgotten us + rabbit_log_prelaunch:debug("Checking cluster consistency"), + rabbit_mnesia:check_cluster_consistency(), + ok. diff --git a/src/rabbit_prelaunch_conf.erl b/src/rabbit_prelaunch_conf.erl new file mode 100644 index 0000000000..23d0f68f82 --- /dev/null +++ b/src/rabbit_prelaunch_conf.erl @@ -0,0 +1,534 @@ +-module(rabbit_prelaunch_conf). + +-include_lib("kernel/include/file.hrl"). +-include_lib("stdlib/include/zip.hrl"). + +-include_lib("rabbit_common/include/rabbit.hrl"). + +-export([setup/1, + get_config_state/0, + generate_config_from_cuttlefish_files/3, + decrypt_config/1]). + +-ifdef(TEST). +-export([decrypt_config/2]). +-endif. + +setup(Context) -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Configuration =="), + + %% TODO: Check if directories/files are inside Mnesia dir. + + %% TODO: Support glob patterns & directories in RABBITMQ_CONFIG_FILE. + %% TODO: Always try parsing of both erlang and cuttlefish formats. + + update_enabled_plugins_file(Context), + + set_default_config(), + + AdvancedConfigFile = find_actual_advanced_config_file(Context), + State = case find_actual_main_config_file(Context) of + {MainConfigFile, erlang} -> + Config = load_erlang_term_based_config_file( + MainConfigFile), + Apps = [App || {App, _} <- Config], + decrypt_config(Apps), + #{config_type => erlang, + config_files => [MainConfigFile], + config_advanced_file => undefined}; + {MainConfigFile, cuttlefish} -> + ConfigFiles = [MainConfigFile], + Config = load_cuttlefish_config_file(Context, + ConfigFiles, + AdvancedConfigFile), + Apps = [App || {App, _} <- Config], + decrypt_config(Apps), + #{config_type => cuttlefish, + config_files => ConfigFiles, + config_advanced_file => AdvancedConfigFile}; + undefined when AdvancedConfigFile =/= undefined -> + rabbit_log_prelaunch:warning( + "Using RABBITMQ_ADVANCED_CONFIG_FILE: ~s", + [AdvancedConfigFile]), + Config = load_erlang_term_based_config_file( + AdvancedConfigFile), + Apps = [App || {App, _} <- Config], + decrypt_config(Apps), + #{config_type => erlang, + config_files => [AdvancedConfigFile], + config_advanced_file => AdvancedConfigFile}; + undefined -> + #{config_type => undefined, + config_files => [], + config_advanced_file => undefined} + end, + override_with_hard_coded_critical_config(), + rabbit_log_prelaunch:debug( + "Saving config state to application env: ~p", [State]), + store_config_state(State). + +store_config_state(ConfigState) -> + persistent_term:put({rabbitmq_prelaunch, config_state}, ConfigState). + +get_config_state() -> + persistent_term:get({rabbitmq_prelaunch, config_state}, undefined). + +%% ------------------------------------------------------------------- +%% `enabled_plugins` file content initialization. +%% ------------------------------------------------------------------- + +update_enabled_plugins_file(Context) -> + %% We only do this on startup, not when the configuration is + %% reloaded. + case get_config_state() of + undefined -> update_enabled_plugins_file1(Context); + _ -> ok + end. + +update_enabled_plugins_file1(#{enabled_plugins := undefined}) -> + ok; +update_enabled_plugins_file1(#{enabled_plugins := all, + plugins_path := Path} = Context) -> + List = [P#plugin.name || P <- rabbit_plugins:list(Path)], + do_update_enabled_plugins_file(Context, List); +update_enabled_plugins_file1(#{enabled_plugins := List} = Context) -> + do_update_enabled_plugins_file(Context, List). + +do_update_enabled_plugins_file(#{enabled_plugins_file := File}, List) -> + SortedList = lists:usort(List), + case SortedList of + [] -> + rabbit_log_prelaunch:debug("Marking all plugins as disabled"); + _ -> + rabbit_log_prelaunch:debug( + "Marking the following plugins as enabled:"), + [rabbit_log_prelaunch:debug(" - ~s", [P]) || P <- SortedList] + end, + Content = io_lib:format("~p.~n", [SortedList]), + case file:write_file(File, Content) of + ok -> + ok; + {error, Reason} -> + rabbit_log_prelaunch:error( + "Failed to update enabled plugins file \"~ts\" " + "from $RABBITMQ_ENABLED_PLUGINS: ~ts", + [File, file:format_error(Reason)]), + throw({error, failed_to_update_enabled_plugins_file}) + end. + +%% ------------------------------------------------------------------- +%% Configuration loading. +%% ------------------------------------------------------------------- + +set_default_config() -> + rabbit_log_prelaunch:debug("Setting default config"), + Config = [ + {ra, + [ + %% Use a larger segments size for queues. + {segment_max_entries, 32768}, + {wal_max_size_bytes, 536870912} %% 5 * 2 ^ 20 + ]}, + {sysmon_handler, + [{process_limit, 100}, + {port_limit, 100}, + {gc_ms_limit, 0}, + {schedule_ms_limit, 0}, + {heap_word_limit, 0}, + {busy_port, false}, + {busy_dist_port, true}]} + ], + apply_erlang_term_based_config(Config). + +find_actual_main_config_file(#{main_config_file := File}) -> + case filelib:is_regular(File) of + true -> + Format = case filename:extension(File) of + ".conf" -> cuttlefish; + ".config" -> erlang; + _ -> determine_config_format(File) + end, + {File, Format}; + false -> + OldFormatFile = File ++ ".config", + NewFormatFile = File ++ ".conf", + case filelib:is_regular(OldFormatFile) of + true -> + case filelib:is_regular(NewFormatFile) of + true -> + rabbit_log_prelaunch:warning( + "Both old (.config) and new (.conf) format config " + "files exist."), + rabbit_log_prelaunch:warning( + "Using the old format config file: ~s", + [OldFormatFile]), + rabbit_log_prelaunch:warning( + "Please update your config files to the new format " + "and remove the old file."), + ok; + false -> + ok + end, + {OldFormatFile, erlang}; + false -> + case filelib:is_regular(NewFormatFile) of + true -> {NewFormatFile, cuttlefish}; + false -> undefined + end + end + end. + +find_actual_advanced_config_file(#{advanced_config_file := File}) -> + case filelib:is_regular(File) of + true -> File; + false -> undefined + end. + +determine_config_format(File) -> + case filelib:file_size(File) of + 0 -> + cuttlefish; + _ -> + case file:consult(File) of + {ok, _} -> erlang; + _ -> cuttlefish + end + end. + +load_erlang_term_based_config_file(ConfigFile) -> + rabbit_log_prelaunch:debug( + "Loading configuration file \"~ts\" (Erlang terms based)", [ConfigFile]), + case file:consult(ConfigFile) of + {ok, [Config]} when is_list(Config) -> + apply_erlang_term_based_config(Config), + Config; + {ok, OtherTerms} -> + rabbit_log_prelaunch:error( + "Failed to load configuration file \"~ts\", " + "incorrect format: ~p", + [ConfigFile, OtherTerms]), + throw({error, failed_to_parse_configuration_file}); + {error, Reason} -> + rabbit_log_prelaunch:error( + "Failed to load configuration file \"~ts\": ~ts", + [ConfigFile, file:format_error(Reason)]), + throw({error, failed_to_read_configuration_file}) + end. + +load_cuttlefish_config_file(Context, + ConfigFiles, + AdvancedConfigFile) -> + Config = generate_config_from_cuttlefish_files( + Context, ConfigFiles, AdvancedConfigFile), + apply_erlang_term_based_config(Config), + Config. + +generate_config_from_cuttlefish_files(Context, + ConfigFiles, + AdvancedConfigFile) -> + %% Load schemas. + SchemaFiles = find_cuttlefish_schemas(Context), + case SchemaFiles of + [] -> + rabbit_log_prelaunch:error( + "No configuration schema found~n", []), + throw({error, no_configuration_schema_found}); + _ -> + rabbit_log_prelaunch:debug( + "Configuration schemas found:~n", []), + [rabbit_log_prelaunch:debug(" - ~ts", [SchemaFile]) + || SchemaFile <- SchemaFiles], + ok + end, + Schema = cuttlefish_schema:files(SchemaFiles), + + %% Load configuration. + rabbit_log_prelaunch:debug( + "Loading configuration files (Cuttlefish based):"), + [rabbit_log_prelaunch:debug( + " - ~ts", [ConfigFile]) || ConfigFile <- ConfigFiles], + case cuttlefish_conf:files(ConfigFiles) of + {errorlist, Errors} -> + rabbit_log_prelaunch:error("Error generating configuration:", []), + [rabbit_log_prelaunch:error( + " - ~ts", + [cuttlefish_error:xlate(Error)]) + || Error <- Errors], + throw({error, failed_to_generate_configuration_file}); + Config0 -> + %% Finalize configuration, based on the schema. + Config = case cuttlefish_generator:map(Schema, Config0) of + {error, Phase, {errorlist, Errors}} -> + %% TODO + rabbit_log_prelaunch:error( + "Error generating configuration in phase ~ts:", + [Phase]), + [rabbit_log_prelaunch:error( + " - ~ts", + [cuttlefish_error:xlate(Error)]) + || Error <- Errors], + throw( + {error, failed_to_generate_configuration_file}); + ValidConfig -> + proplists:delete(vm_args, ValidConfig) + end, + + %% Apply advanced configuration overrides, if any. + override_with_advanced_config(Config, AdvancedConfigFile) + end. + +find_cuttlefish_schemas(Context) -> + Apps = list_apps(Context), + rabbit_log_prelaunch:debug( + "Looking up configuration schemas in the following applications:"), + find_cuttlefish_schemas(Apps, []). + +find_cuttlefish_schemas([App | Rest], AllSchemas) -> + Schemas = list_schemas_in_app(App), + find_cuttlefish_schemas(Rest, AllSchemas ++ Schemas); +find_cuttlefish_schemas([], AllSchemas) -> + lists:sort(fun(A,B) -> A < B end, AllSchemas). + +list_apps(#{os_type := {win32, _}, plugins_path := PluginsPath}) -> + PluginsDirs = string:lexemes(PluginsPath, ";"), + list_apps1(PluginsDirs, []); +list_apps(#{plugins_path := PluginsPath}) -> + PluginsDirs = string:lexemes(PluginsPath, ":"), + list_apps1(PluginsDirs, []). + + +list_apps1([Dir | Rest], Apps) -> + case file:list_dir(Dir) of + {ok, Filenames} -> + NewApps = [list_to_atom( + hd( + string:split(filename:basename(F, ".ex"), "-"))) + || F <- Filenames], + Apps1 = lists:umerge(Apps, lists:sort(NewApps)), + list_apps1(Rest, Apps1); + {error, Reason} -> + rabbit_log_prelaunch:debug( + "Failed to list directory \"~ts\" content: ~ts", + [Dir, file:format_error(Reason)]), + list_apps1(Rest, Apps) + end; +list_apps1([], AppInfos) -> + AppInfos. + +list_schemas_in_app(App) -> + {Loaded, Unload} = case application:load(App) of + ok -> {true, true}; + {error, {already_loaded, _}} -> {true, false}; + {error, _} -> {false, false} + end, + List = case Loaded of + true -> + case code:priv_dir(App) of + {error, bad_name} -> + rabbit_log_prelaunch:debug( + " [ ] ~s (no readable priv dir)", [App]), + []; + PrivDir -> + SchemaDir = filename:join([PrivDir, "schema"]), + do_list_schemas_in_app(App, SchemaDir) + end; + false -> + rabbit_log_prelaunch:debug( + " [ ] ~s (failed to load application)", [App]), + [] + end, + case Unload of + true -> application:unload(App); + false -> ok + end, + List. + +do_list_schemas_in_app(App, SchemaDir) -> + case erl_prim_loader:list_dir(SchemaDir) of + {ok, Files} -> + rabbit_log_prelaunch:debug(" [x] ~s", [App]), + [filename:join(SchemaDir, File) + || [C | _] = File <- Files, + C =/= $.]; + error -> + rabbit_log_prelaunch:debug( + " [ ] ~s (no readable schema dir)", [App]), + [] + end. + +override_with_advanced_config(Config, undefined) -> + Config; +override_with_advanced_config(Config, AdvancedConfigFile) -> + rabbit_log_prelaunch:debug( + "Override with advanced configuration file \"~ts\"", + [AdvancedConfigFile]), + case file:consult(AdvancedConfigFile) of + {ok, [AdvancedConfig]} -> + cuttlefish_advanced:overlay(Config, AdvancedConfig); + {ok, OtherTerms} -> + rabbit_log_prelaunch:error( + "Failed to load advanced configuration file \"~ts\", " + "incorrect format: ~p", + [AdvancedConfigFile, OtherTerms]), + throw({error, failed_to_parse_advanced_configuration_file}); + {error, Reason} -> + rabbit_log_prelaunch:error( + "Failed to load advanced configuration file \"~ts\": ~ts", + [AdvancedConfigFile, file:format_error(Reason)]), + throw({error, failed_to_read_advanced_configuration_file}) + end. + +override_with_hard_coded_critical_config() -> + rabbit_log_prelaunch:debug("Override with hard-coded critical config"), + Config = [ + {ra, + %% Make Ra use a custom logger that dispatches to lager + %% instead of the default OTP logger + [{logger_module, rabbit_log_ra_shim}]} + ], + apply_erlang_term_based_config(Config). + +apply_erlang_term_based_config([{_, []} | Rest]) -> + apply_erlang_term_based_config(Rest); +apply_erlang_term_based_config([{App, Vars} | Rest]) -> + rabbit_log_prelaunch:debug(" Applying configuration for '~s':", [App]), + apply_app_env_vars(App, Vars), + apply_erlang_term_based_config(Rest); +apply_erlang_term_based_config([]) -> + ok. + +apply_app_env_vars(App, [{Var, Value} | Rest]) -> + rabbit_log_prelaunch:debug( + " - ~s = ~p", + [Var, Value]), + ok = application:set_env(App, Var, Value, [{persistent, true}]), + apply_app_env_vars(App, Rest); +apply_app_env_vars(_, []) -> + ok. + +%% ------------------------------------------------------------------- +%% Config decryption. +%% ------------------------------------------------------------------- + +decrypt_config(Apps) -> + rabbit_log_prelaunch:debug("Decoding encrypted config values (if any)"), + ConfigEntryDecoder = application:get_env(rabbit, config_entry_decoder, []), + decrypt_config(Apps, ConfigEntryDecoder). + +decrypt_config([], _) -> + ok; +decrypt_config([App | Apps], Algo) -> + Algo1 = decrypt_app(App, application:get_all_env(App), Algo), + decrypt_config(Apps, Algo1). + +decrypt_app(_, [], Algo) -> + Algo; +decrypt_app(App, [{Key, Value} | Tail], Algo) -> + Algo2 = try + case decrypt(Value, Algo) of + {Value, Algo1} -> + Algo1; + {NewValue, Algo1} -> + rabbit_log_prelaunch:debug( + "Value of `~s` decrypted", [Key]), + ok = application:set_env(App, Key, NewValue, + [{persistent, true}]), + Algo1 + end + catch + throw:{bad_config_entry_decoder, _} = Error -> + throw(Error); + _:Msg -> + throw({config_decryption_error, {key, Key}, Msg}) + end, + decrypt_app(App, Tail, Algo2). + +decrypt({encrypted, EncValue}, + {Cipher, Hash, Iterations, PassPhrase} = Algo) -> + {rabbit_pbe:decrypt_term(Cipher, Hash, Iterations, PassPhrase, EncValue), + Algo}; +decrypt({encrypted, _} = Value, + ConfigEntryDecoder) + when is_list(ConfigEntryDecoder) -> + Algo = config_entry_decoder_to_algo(ConfigEntryDecoder), + decrypt(Value, Algo); +decrypt(List, Algo) when is_list(List) -> + decrypt_list(List, Algo, []); +decrypt(Value, Algo) -> + {Value, Algo}. + +%% We make no distinction between strings and other lists. +%% When we receive a string, we loop through each element +%% and ultimately return the string unmodified, as intended. +decrypt_list([], Algo, Acc) -> + {lists:reverse(Acc), Algo}; +decrypt_list([{Key, Value} | Tail], Algo, Acc) + when Key =/= encrypted -> + {Value1, Algo1} = decrypt(Value, Algo), + decrypt_list(Tail, Algo1, [{Key, Value1} | Acc]); +decrypt_list([Value | Tail], Algo, Acc) -> + {Value1, Algo1} = decrypt(Value, Algo), + decrypt_list(Tail, Algo1, [Value1 | Acc]). + +config_entry_decoder_to_algo(ConfigEntryDecoder) -> + case get_passphrase(ConfigEntryDecoder) of + undefined -> + throw({bad_config_entry_decoder, missing_passphrase}); + PassPhrase -> + { + proplists:get_value( + cipher, ConfigEntryDecoder, rabbit_pbe:default_cipher()), + proplists:get_value( + hash, ConfigEntryDecoder, rabbit_pbe:default_hash()), + proplists:get_value( + iterations, ConfigEntryDecoder, rabbit_pbe:default_iterations()), + PassPhrase + } + end. + +get_passphrase(ConfigEntryDecoder) -> + rabbit_log_prelaunch:debug("Getting encrypted config passphrase"), + case proplists:get_value(passphrase, ConfigEntryDecoder) of + prompt -> + IoDevice = get_input_iodevice(), + io:setopts(IoDevice, [{echo, false}]), + PP = lists:droplast(io:get_line(IoDevice, + "\nPlease enter the passphrase to unlock encrypted " + "configuration entries.\n\nPassphrase: ")), + io:setopts(IoDevice, [{echo, true}]), + io:format(IoDevice, "~n", []), + PP; + {file, Filename} -> + {ok, File} = file:read_file(Filename), + [PP|_] = binary:split(File, [<<"\r\n">>, <<"\n">>]), + PP; + PP -> + PP + end. + +%% This function retrieves the correct IoDevice for requesting +%% input. The problem with using the default IoDevice is that +%% the Erlang shell prevents us from getting the input. +%% +%% Instead we therefore look for the io process used by the +%% shell and if it can't be found (because the shell is not +%% started e.g with -noshell) we use the 'user' process. +%% +%% This function will not work when either -oldshell or -noinput +%% options are passed to erl. +get_input_iodevice() -> + case whereis(user) of + undefined -> + user; + User -> + case group:interfaces(User) of + [] -> + user; + [{user_drv, Drv}] -> + case user_drv:interfaces(Drv) of + [] -> user; + [{current_group, IoDevice}] -> IoDevice + end + end + end. diff --git a/src/rabbit_prelaunch_feature_flags.erl b/src/rabbit_prelaunch_feature_flags.erl new file mode 100644 index 0000000000..cef656078a --- /dev/null +++ b/src/rabbit_prelaunch_feature_flags.erl @@ -0,0 +1,25 @@ +-module(rabbit_prelaunch_feature_flags). + +-export([setup/1]). + +setup(#{feature_flags_file := FFFile}) -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Feature flags =="), + case filelib:ensure_dir(FFFile) of + ok -> + rabbit_log_prelaunch:debug("Initializing feature flags registry"), + case rabbit_feature_flags:initialize_registry() of + ok -> + ok; + {error, Reason} -> + rabbit_log_prelaunch:error( + "Failed to initialize feature flags registry: ~p", + [Reason]), + throw({error, failed_to_initialize_feature_flags_registry}) + end; + {error, Reason} -> + rabbit_log_prelaunch:error( + "Failed to create feature flags file \"~ts\" directory: ~ts", + [FFFile, file:format_error(Reason)]), + throw({error, failed_to_create_feature_flags_file_directory}) + end. diff --git a/src/rabbit_prelaunch_hipe.erl b/src/rabbit_prelaunch_hipe.erl new file mode 100644 index 0000000000..16e9b90869 --- /dev/null +++ b/src/rabbit_prelaunch_hipe.erl @@ -0,0 +1,10 @@ +-module(rabbit_prelaunch_hipe). + +-export([setup/1]). + +setup(_Context) -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== HiPE compitation =="), + HipeResult = rabbit_hipe:maybe_hipe_compile(), + rabbit_hipe:log_hipe_result(HipeResult), + ok. diff --git a/src/rabbit_prelaunch_logging.erl b/src/rabbit_prelaunch_logging.erl new file mode 100644 index 0000000000..5d70d46f86 --- /dev/null +++ b/src/rabbit_prelaunch_logging.erl @@ -0,0 +1,68 @@ +-module(rabbit_prelaunch_logging). + +-export([setup/1]). + +setup(Context) -> + rabbit_log_prelaunch:debug(""), + rabbit_log_prelaunch:debug("== Logging =="), + ok = set_ERL_CRASH_DUMP_envvar(Context), + ok = configure_lager(Context). + +set_ERL_CRASH_DUMP_envvar(#{log_base_dir := LogBaseDir}) -> + case os:getenv("ERL_CRASH_DUMP") of + false -> + ErlCrashDump = filename:join(LogBaseDir, "erl_crash.dump"), + rabbit_log_prelaunch:debug( + "Setting $ERL_CRASH_DUMP environment variable to \"~ts\"", + [ErlCrashDump]), + os:putenv("ERL_CRASH_DUMP", ErlCrashDump), + ok; + ErlCrashDump -> + rabbit_log_prelaunch:debug( + "$ERL_CRASH_DUMP environment variable already set to \"~ts\"", + [ErlCrashDump]), + ok + end. + +configure_lager(#{log_base_dir := LogBaseDir, + main_log_file := MainLog, + upgrade_log_file := UpgradeLog} = Context) -> + {SaslErrorLogger, + MainLagerHandler, + UpgradeLagerHandler} = case MainLog of + "-" -> + %% Log to STDOUT. + rabbit_log_prelaunch:debug( + "Logging to stdout"), + {tty, + tty, + tty}; + _ -> + rabbit_log_prelaunch:debug( + "Logging to:"), + [rabbit_log_prelaunch:debug( + " - ~ts", [Log]) + || Log <- [MainLog, UpgradeLog]], + %% Log to file. + {false, + MainLog, + UpgradeLog} + end, + + ok = application:set_env(lager, crash_log, "log/crash.log"), + + Fun = fun({App, Var, Value}) -> + case application:get_env(App, Var) of + undefined -> ok = application:set_env(App, Var, Value); + _ -> ok + end + end, + Vars = [{sasl, sasl_error_logger, SaslErrorLogger}, + {rabbit, lager_log_root, LogBaseDir}, + {rabbit, lager_default_file, MainLagerHandler}, + {rabbit, lager_upgrade_file, UpgradeLagerHandler}], + lists:foreach(Fun, Vars), + + ok = rabbit_lager:start_logger(), + + ok = rabbit_prelaunch_early_logging:setup_early_logging(Context, false). diff --git a/src/rabbit_table.erl b/src/rabbit_table.erl index 8326666edd..c14b829841 100644 --- a/src/rabbit_table.erl +++ b/src/rabbit_table.erl @@ -106,9 +106,11 @@ wait(TableNames, Timeout, Retries) -> ok -> ok; {timeout, BadTabs} -> - {error, {timeout_waiting_for_tables, BadTabs}}; + AllNodes = rabbit_mnesia:cluster_nodes(all), + {error, {timeout_waiting_for_tables, AllNodes, BadTabs}}; {error, Reason} -> - {error, {failed_waiting_for_tables, Reason}} + AllNodes = rabbit_mnesia:cluster_nodes(all), + {error, {failed_waiting_for_tables, AllNodes, Reason}} end, case {Retries, Result} of {_, ok} -> diff --git a/test/clustering_management_SUITE.erl b/test/clustering_management_SUITE.erl index 90bb75636e..7335767398 100644 --- a/test/clustering_management_SUITE.erl +++ b/test/clustering_management_SUITE.erl @@ -224,8 +224,7 @@ join_cluster_bad_operations(Config) -> ok = stop_app(Hare), assert_failure(fun () -> start_app(Hare) end), ok = start_app(Rabbit), - %% The Erlang VM has stopped after previous rabbit app failure - ok = rabbit_ct_broker_helpers:start_node(Config, Hare), + ok = start_app(Hare), ok. %% This tests that the nodes in the cluster are notified immediately of a node diff --git a/test/feature_flags_SUITE.erl b/test/feature_flags_SUITE.erl index 16f11733d5..8f672314f0 100644 --- a/test/feature_flags_SUITE.erl +++ b/test/feature_flags_SUITE.erl @@ -136,14 +136,18 @@ init_per_group(clustering, Config) -> [{rmq_nodes_count, 2}, {rmq_nodes_clustered, false}, {start_rmq_with_plugins_disabled, true}]), - build_my_plugin(Config1); + rabbit_ct_helpers:run_setup_steps(Config1, [ + fun build_my_plugin/1 + ]); init_per_group(activating_plugin, Config) -> Config1 = rabbit_ct_helpers:set_config( Config, [{rmq_nodes_count, 2}, {rmq_nodes_clustered, true}, {start_rmq_with_plugins_disabled, true}]), - build_my_plugin(Config1); + rabbit_ct_helpers:run_setup_steps(Config1, [ + fun build_my_plugin/1 + ]); init_per_group(_, Config) -> Config. @@ -910,13 +914,31 @@ build_my_plugin(Config) -> {ok, _} -> {_, OtherPlugins1} = list_my_plugin_plugins(PluginSrcDir), remove_other_plugins(PluginSrcDir, OtherPlugins1), - Config1; + update_cli_path(Config1, PluginSrcDir); {error, _} -> {skip, "Failed to compile the `my_plugin` test plugin"} end; _ -> remove_other_plugins(PluginSrcDir, OtherPlugins), - Config1 + update_cli_path(Config1, PluginSrcDir) + end. + +update_cli_path(Config, PluginSrcDir) -> + SbinDir = filename:join(PluginSrcDir, "sbin"), + Rabbitmqctl = filename:join(SbinDir, "rabbitmqctl"), + RabbitmqPlugins = filename:join(SbinDir, "rabbitmq-plugins"), + RabbitmqQueues = filename:join(SbinDir, "rabbitmq-queues"), + case filelib:is_regular(Rabbitmqctl) of + true -> + ct:pal(?LOW_IMPORTANCE, + "Switching to CLI in e.g. ~s", [Rabbitmqctl]), + rabbit_ct_helpers:set_config( + Config, + [{rabbitmqctl_cmd, Rabbitmqctl}, + {rabbitmq_plugins_cmd, RabbitmqPlugins}, + {rabbitmq_queues_cmd, RabbitmqQueues}]); + false -> + Config end. list_my_plugin_plugins(PluginSrcDir) -> diff --git a/test/unit_SUITE.erl b/test/unit_SUITE.erl index 2bea590342..e8abd2ae90 100644 --- a/test/unit_SUITE.erl +++ b/test/unit_SUITE.erl @@ -44,8 +44,6 @@ groups() -> ]}, content_framing, content_transcoding, - decrypt_config, - listing_plugins_from_multiple_directories, rabbitmqctl_encode, pmerge, plmerge, @@ -72,7 +70,9 @@ groups() -> decrypt_start_app, decrypt_start_app_file, decrypt_start_app_undefined, - decrypt_start_app_wrong_passphrase + decrypt_start_app_wrong_passphrase, + decrypt_config, + listing_plugins_from_multiple_directories ]} ]. @@ -81,20 +81,13 @@ end_per_group(_, Config) -> Config. init_per_testcase(TC, Config) when TC =:= decrypt_start_app; TC =:= decrypt_start_app_file; - TC =:= decrypt_start_app_undefined -> - application:load(rabbit), - application:set_env(rabbit, feature_flags_file, ""), + TC =:= decrypt_start_app_undefined; + TC =:= decrypt_start_app_wrong_passphrase -> + application:set_env(rabbit, feature_flags_file, "", [{persistent, true}]), Config; init_per_testcase(_Testcase, Config) -> Config. -end_per_testcase(TC, _Config) when TC =:= decrypt_start_app; - TC =:= decrypt_start_app_file; - TC =:= decrypt_start_app_undefined -> - application:unload(rabbit), - application:unload(rabbit_shovel_test); -end_per_testcase(decrypt_config, _Config) -> - application:unload(rabbit); end_per_testcase(_TC, _Config) -> ok. @@ -177,7 +170,7 @@ decrypt_config(_Config) -> ok. do_decrypt_config(Algo = {C, H, I, P}) -> - application:load(rabbit), + ok = application:load(rabbit), RabbitConfig = application:get_all_env(rabbit), %% Encrypt a few values in configuration. %% Common cases. @@ -205,10 +198,10 @@ do_decrypt_config(Algo = {C, H, I, P}) -> TCPOpts2 = lists:keyreplace(linger, 1, TCPOpts1, {linger, {encrypted, EncLinger}}), application:set_env(rabbit, tcp_listen_options, TCPOpts2), %% Decrypt configuration. - rabbit:decrypt_config([rabbit], Algo), + rabbit_prelaunch_conf:decrypt_config([rabbit], Algo), %% Check that configuration was decrypted properly. RabbitConfig = application:get_all_env(rabbit), - application:unload(rabbit), + ok = application:unload(rabbit), ok. encrypt_value(Key, {C, H, I, P}) -> @@ -229,7 +222,7 @@ do_decrypt_start_app(Config, Passphrase) -> {hash, sha512}, {iterations, 1000}, {passphrase, Passphrase} - ]), + ], [{persistent, true}]), %% Add the path to our test application. code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), %% Attempt to start our test application. @@ -256,7 +249,7 @@ decrypt_start_app_undefined(Config) -> {hash, sha512}, {iterations, 1000} %% No passphrase option! - ]), + ], [{persistent, true}]), %% Add the path to our test application. code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), %% Attempt to start our test application. @@ -265,7 +258,7 @@ decrypt_start_app_undefined(Config) -> try rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) catch - exit:{bad_configuration, config_entry_decoder} -> ok; + throw:{bad_config_entry_decoder, missing_passphrase} -> ok; _:Exception -> exit({unexpected_exception, Exception}) end. @@ -276,7 +269,7 @@ decrypt_start_app_wrong_passphrase(Config) -> {hash, sha512}, {iterations, 1000}, {passphrase, "wrong passphrase"} - ]), + ], [{persistent, true}]), %% Add the path to our test application. code:add_path(?config(data_dir, Config) ++ "/lib/rabbit_shovel_test/ebin"), %% Attempt to start our test application. @@ -285,7 +278,7 @@ decrypt_start_app_wrong_passphrase(Config) -> try rabbit:start_apps([rabbit_shovel_test], #{rabbit => temporary}) catch - exit:{decryption_error,_,_} -> ok; + throw:{config_decryption_error, _, _} -> ok; _:Exception -> exit({unexpected_exception, Exception}) end. @@ -961,6 +954,10 @@ listing_plugins_from_multiple_directories(Config) -> end, Path = FirstDir ++ PathSep ++ SecondDir, Got = lists:sort([{Name, Vsn} || #plugin{name = Name, version = Vsn} <- rabbit_plugins:list(Path)]), + %% `rabbit` was loaded automatically by `rabbit_plugins:list/1`. + %% We want to unload it now so it does not interfere with other + %% testcases. + application:unload(rabbit), Expected = [{plugin_both, "2"}, {plugin_first_dir, "3"}, {plugin_second_dir, "4"}], case Got of Expected -> diff --git a/test/unit_inbroker_non_parallel_SUITE.erl b/test/unit_inbroker_non_parallel_SUITE.erl index 120a7fdbd9..2b4a216977 100644 --- a/test/unit_inbroker_non_parallel_SUITE.erl +++ b/test/unit_inbroker_non_parallel_SUITE.erl @@ -503,7 +503,7 @@ log_file_fails_to_initialise_during_startup1(_Config, NonWritableDir) -> ok -> exit({got_success_but_expected_failure, log_rotation_no_write_permission_dir_test}) catch - _:could_not_initialise_logger -> ok + throw:{error, {rabbit, {{cannot_log_to_file, _, _}, _}}} -> ok end, %% start application with logging to a subdirectory which @@ -530,7 +530,7 @@ log_file_fails_to_initialise_during_startup1(_Config, NonWritableDir) -> ok -> exit({got_success_but_expected_failure, log_rotation_parent_dirs_test}) catch - _:could_not_initialise_logger -> ok + throw:{error, {rabbit, {{cannot_log_to_file, _, _}, _}}} -> ok end, %% clean up diff --git a/test/unit_log_config_SUITE.erl b/test/unit_log_config_SUITE.erl index 93c050edda..a13c90a362 100644 --- a/test/unit_log_config_SUITE.erl +++ b/test/unit_log_config_SUITE.erl @@ -132,6 +132,9 @@ sink_rewrite_sinks() -> {rabbit_log_mirroring_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, + {rabbit_log_prelaunch_lager_event, + [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, + {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, {rabbit_log_queue_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, @@ -225,6 +228,9 @@ sink_handlers_merged_with_lager_extra_sinks_handlers(_) -> {rabbit_log_mirroring_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, + {rabbit_log_prelaunch_lager_event, + [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, + {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, {rabbit_log_queue_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, @@ -285,7 +291,7 @@ config_sinks_level(_) -> rabbit_lager:configure_lager(), ExpectedSinks = sort_sinks(level_sinks()), - ExpectedSinks = sort_sinks(application:get_env(lager, extra_sinks, undefined)). + ?assertEqual(ExpectedSinks, sort_sinks(application:get_env(lager, extra_sinks, undefined))). level_sinks() -> [{error_logger_lager_event, @@ -310,6 +316,9 @@ level_sinks() -> {rabbit_log_mirroring_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,error]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,error]}]}]}, + {rabbit_log_prelaunch_lager_event, + [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, + {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, {rabbit_log_queue_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, @@ -409,6 +418,9 @@ file_sinks() -> {rabbit_log_mirroring_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, + {rabbit_log_prelaunch_lager_event, + [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, + {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, {rabbit_log_queue_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, @@ -650,6 +662,9 @@ default_expected_sinks(UpgradeFile) -> {rabbit_log_mirroring_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, + {rabbit_log_prelaunch_lager_event, + [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, + {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, {rabbit_log_queue_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, @@ -722,6 +737,9 @@ tty_expected_sinks() -> {rabbit_log_mirroring_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, + {rabbit_log_prelaunch_lager_event, + [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, + {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, {rabbit_log_queue_lager_event, [{handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}, {rabbit_handlers,[{lager_forwarder_backend,[lager_event,inherit]}]}]}, |
