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).
			
			
This commit is contained in:
		
							parent
							
								
									5e6043ac59
								
							
						
					
					
						commit
						68c30553cc
					
				|  | @ -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. | ||||
|  |  | |||
							
								
								
									
										31
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										31
									
								
								Makefile
								
								
								
								
							|  | @ -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 | ||||
|  |  | |||
|  | @ -0,0 +1,12 @@ | |||
| *~ | ||||
| .sw? | ||||
| .*.sw? | ||||
| *.beam | ||||
| *.coverdata | ||||
| /ebin/ | ||||
| /.erlang.mk/ | ||||
| /rabbitmq_prelaunch.d | ||||
| /xrefr | ||||
| 
 | ||||
| # Dialyzer | ||||
| *.plt | ||||
|  | @ -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 | ||||
|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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). | ||||
|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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}}. | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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" "$@" | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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. | ||||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										681
									
								
								src/rabbit.erl
								
								
								
								
							
							
						
						
									
										681
									
								
								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). | ||||
|     %% 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). | ||||
| 
 | ||||
| ensure_config() -> | ||||
|     case rabbit_config:validate_config_files() of | ||||
|         ok -> ok; | ||||
|         {error, {ErrFmt, ErrArgs}} -> | ||||
|             throw({error, {check_config_file, ErrFmt, ErrArgs}}) | ||||
| 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, | ||||
|     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. | ||||
|     %% 1. Feature flags registry. | ||||
|     ok = rabbit_prelaunch_feature_flags: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())). | ||||
|     %% 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, | ||||
| 
 | ||||
|     %% 5. Clustering. | ||||
|     ok = rabbit_prelaunch_cluster:setup(Context), | ||||
| 
 | ||||
|     %% 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" | ||||
|  |  | |||
|  | @ -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 | ||||
|         undefined   -> | ||||
|             case application:get_env(rabbitmq_prelaunch, context) of | ||||
|                 #{main_config_file := File2} -> File2; | ||||
|                 _                            -> none | ||||
|             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} | ||||
|     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]}}. | ||||
|  |  | |||
|  | @ -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() -> | ||||
|  |  | |||
|  | @ -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()]. | ||||
|  |  | |||
|  | @ -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). | ||||
|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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. | ||||
|  | @ -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). | ||||
|  | @ -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} -> | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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) -> | ||||
|  |  | |||
|  | @ -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 -> | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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]}]}]}, | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue