2019-09-03 23:28:30 +08:00
|
|
|
%% 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) 2019 Pivotal Software, Inc. All rights reserved.
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
|
|
-module(rabbit_env).
|
|
|
|
|
|
|
|
|
|
-include_lib("kernel/include/file.hrl").
|
|
|
|
|
|
|
|
|
|
-export([get_context/0,
|
|
|
|
|
get_context/1,
|
|
|
|
|
get_context_before_logging_init/0,
|
|
|
|
|
get_context_before_logging_init/1,
|
|
|
|
|
get_context_after_logging_init/1,
|
|
|
|
|
get_context_after_reloading_env/1,
|
|
|
|
|
dbg_config/0,
|
|
|
|
|
log_process_env/0,
|
|
|
|
|
log_context/1,
|
|
|
|
|
context_to_app_env_vars/1,
|
|
|
|
|
context_to_app_env_vars_no_logging/1,
|
|
|
|
|
context_to_code_path/1]).
|
|
|
|
|
|
|
|
|
|
-ifdef(TEST).
|
|
|
|
|
-export([value_is_yes/1]).
|
|
|
|
|
-endif.
|
|
|
|
|
|
|
|
|
|
-define(USED_ENV_VARS,
|
|
|
|
|
[
|
|
|
|
|
"RABBITMQ_ALLOW_INPUT",
|
|
|
|
|
"RABBITMQ_ADVANCED_CONFIG_FILE",
|
|
|
|
|
"RABBITMQ_BASE",
|
|
|
|
|
"RABBITMQ_CONF_ENV_FILE",
|
|
|
|
|
"RABBITMQ_CONFIG_FILE",
|
|
|
|
|
"RABBITMQ_DBG",
|
|
|
|
|
"RABBITMQ_DIST_PORT",
|
|
|
|
|
"RABBITMQ_ENABLED_PLUGINS",
|
|
|
|
|
"RABBITMQ_ENABLED_PLUGINS_FILE",
|
2020-01-21 01:38:59 +08:00
|
|
|
"RABBITMQ_FEATURE_FLAGS",
|
2019-09-03 23:28:30 +08:00
|
|
|
"RABBITMQ_FEATURE_FLAGS_FILE",
|
|
|
|
|
"RABBITMQ_HOME",
|
|
|
|
|
"RABBITMQ_KEEP_PID_FILE_ON_EXIT",
|
|
|
|
|
"RABBITMQ_LOG",
|
|
|
|
|
"RABBITMQ_LOG_BASE",
|
2020-01-21 01:38:59 +08:00
|
|
|
"RABBITMQ_LOG_FF_REGISTRY",
|
2019-09-03 23:28:30 +08:00
|
|
|
"RABBITMQ_LOGS",
|
|
|
|
|
"RABBITMQ_MNESIA_BASE",
|
|
|
|
|
"RABBITMQ_MNESIA_DIR",
|
|
|
|
|
"RABBITMQ_NODE_IP_ADDRESS",
|
|
|
|
|
"RABBITMQ_NODE_PORT",
|
|
|
|
|
"RABBITMQ_NODENAME",
|
|
|
|
|
"RABBITMQ_PID_FILE",
|
|
|
|
|
"RABBITMQ_PLUGINS_DIR",
|
|
|
|
|
"RABBITMQ_PLUGINS_EXPAND_DIR",
|
|
|
|
|
"RABBITMQ_QUORUM_DIR",
|
|
|
|
|
"RABBITMQ_UPGRADE_LOG",
|
|
|
|
|
"RABBITMQ_USE_LONGNAME",
|
|
|
|
|
"SYS_PREFIX"
|
|
|
|
|
]).
|
|
|
|
|
|
|
|
|
|
get_context() ->
|
|
|
|
|
Context0 = get_context_before_logging_init(),
|
|
|
|
|
Context1 = get_context_after_logging_init(Context0),
|
|
|
|
|
get_context_after_reloading_env(Context1).
|
|
|
|
|
|
|
|
|
|
get_context(TakeFromRemoteNode) ->
|
|
|
|
|
Context0 = get_context_before_logging_init(TakeFromRemoteNode),
|
|
|
|
|
Context1 = get_context_after_logging_init(Context0),
|
|
|
|
|
get_context_after_reloading_env(Context1).
|
|
|
|
|
|
|
|
|
|
get_context_before_logging_init() ->
|
|
|
|
|
get_context_before_logging_init(false).
|
|
|
|
|
|
|
|
|
|
get_context_before_logging_init(TakeFromRemoteNode) ->
|
|
|
|
|
%% The order of steps below is important because some of them
|
|
|
|
|
%% depends on previous steps.
|
|
|
|
|
Steps = [
|
2020-01-21 01:38:59 +08:00
|
|
|
fun os_type/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun log_levels/1,
|
2020-01-21 01:38:59 +08:00
|
|
|
fun interactive_shell/1,
|
|
|
|
|
fun output_supports_colors/1
|
2019-09-03 23:28:30 +08:00
|
|
|
],
|
|
|
|
|
|
|
|
|
|
run_context_steps(context_base(TakeFromRemoteNode), Steps).
|
|
|
|
|
|
|
|
|
|
get_context_after_logging_init(Context) ->
|
|
|
|
|
%% The order of steps below is important because some of them
|
|
|
|
|
%% depends on previous steps.
|
|
|
|
|
Steps = [
|
2020-01-21 01:38:59 +08:00
|
|
|
fun sys_prefix/1,
|
|
|
|
|
fun rabbitmq_base/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun data_dir/1,
|
2020-01-21 01:38:59 +08:00
|
|
|
fun rabbitmq_home/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun config_base_dir/1,
|
|
|
|
|
fun load_conf_env_file/1,
|
|
|
|
|
fun log_levels/1
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
run_context_steps(Context, Steps).
|
|
|
|
|
|
|
|
|
|
get_context_after_reloading_env(Context) ->
|
|
|
|
|
%% The order of steps below is important because some of them
|
|
|
|
|
%% depends on previous steps.
|
|
|
|
|
Steps = [
|
2020-01-21 01:38:59 +08:00
|
|
|
fun nodename_type/1,
|
|
|
|
|
fun nodename/1,
|
|
|
|
|
fun split_nodename/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun maybe_setup_dist_for_remote_query/1,
|
|
|
|
|
fun dbg_config/1,
|
2020-01-21 01:38:59 +08:00
|
|
|
fun main_config_file/1,
|
|
|
|
|
fun advanced_config_file/1,
|
|
|
|
|
fun log_base_dir/1,
|
|
|
|
|
fun main_log_file/1,
|
|
|
|
|
fun upgrade_log_file/1,
|
|
|
|
|
fun mnesia_base_dir/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun mnesia_dir/1,
|
2020-01-21 01:38:59 +08:00
|
|
|
fun quorum_queue_dir/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun pid_file/1,
|
2020-01-21 01:38:59 +08:00
|
|
|
fun keep_pid_file_on_exit/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun feature_flags_file/1,
|
2020-01-21 01:38:59 +08:00
|
|
|
fun forced_feature_flags_on_init/1,
|
|
|
|
|
fun log_feature_flags_registry/1,
|
|
|
|
|
fun plugins_path/1,
|
|
|
|
|
fun plugins_expand_dir/1,
|
|
|
|
|
fun enabled_plugins_file/1,
|
|
|
|
|
fun enabled_plugins/1,
|
2019-09-03 23:28:30 +08:00
|
|
|
fun maybe_stop_dist_for_remote_query/1,
|
2020-01-21 01:38:59 +08:00
|
|
|
fun amqp_ipaddr/1,
|
|
|
|
|
fun amqp_tcp_port/1,
|
|
|
|
|
fun erlang_dist_tcp_port/1
|
2019-09-03 23:28:30 +08:00
|
|
|
],
|
|
|
|
|
|
|
|
|
|
run_context_steps(Context, Steps).
|
|
|
|
|
|
|
|
|
|
context_base(TakeFromRemoteNode) ->
|
2020-01-21 01:38:59 +08:00
|
|
|
Context = #{},
|
2019-09-03 23:28:30 +08:00
|
|
|
case TakeFromRemoteNode of
|
|
|
|
|
false ->
|
|
|
|
|
Context;
|
|
|
|
|
offline ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context,
|
|
|
|
|
from_remote_node,
|
|
|
|
|
offline);
|
2019-09-03 23:28:30 +08:00
|
|
|
_ when is_atom(TakeFromRemoteNode) ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context,
|
|
|
|
|
from_remote_node,
|
|
|
|
|
{TakeFromRemoteNode, 10000});
|
2019-09-03 23:28:30 +08:00
|
|
|
{RemoteNode, infinity}
|
|
|
|
|
when is_atom(RemoteNode) ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context,
|
|
|
|
|
from_remote_node,
|
|
|
|
|
TakeFromRemoteNode);
|
2019-09-03 23:28:30 +08:00
|
|
|
{RemoteNode, Timeout}
|
|
|
|
|
when is_atom(RemoteNode) andalso
|
|
|
|
|
is_integer(Timeout) andalso
|
|
|
|
|
Timeout >= 0 ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context,
|
|
|
|
|
from_remote_node,
|
|
|
|
|
{TakeFromRemoteNode, Timeout})
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
-ifdef(TEST).
|
2020-01-21 01:38:59 +08:00
|
|
|
os_type(Context) ->
|
|
|
|
|
{OSType, Origin} =
|
|
|
|
|
try
|
|
|
|
|
{persistent_term:get({?MODULE, os_type}), environment}
|
|
|
|
|
catch
|
|
|
|
|
_:badarg ->
|
|
|
|
|
{os:type(), default}
|
|
|
|
|
end,
|
|
|
|
|
update_context(Context, os_type, OSType, Origin).
|
2019-09-03 23:28:30 +08:00
|
|
|
-else.
|
2020-01-21 01:38:59 +08:00
|
|
|
os_type(Context) ->
|
|
|
|
|
update_context(Context, os_type, os:type(), default).
|
2019-09-03 23:28:30 +08:00
|
|
|
-endif.
|
|
|
|
|
|
|
|
|
|
run_context_steps(Context, Steps) ->
|
|
|
|
|
lists:foldl(
|
|
|
|
|
fun(Step, Context1) -> Step(Context1) end,
|
|
|
|
|
Context,
|
|
|
|
|
Steps).
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, Key, Value) ->
|
|
|
|
|
Context#{Key => Value}.
|
|
|
|
|
|
|
|
|
|
-define(origin_is_valid(O),
|
|
|
|
|
O =:= default orelse
|
|
|
|
|
O =:= environment orelse
|
|
|
|
|
O =:= remote_node).
|
|
|
|
|
|
|
|
|
|
update_context(#{var_origins := Origins} = Context, Key, Value, Origin)
|
|
|
|
|
when ?origin_is_valid(Origin) ->
|
|
|
|
|
Context#{Key => Value,
|
|
|
|
|
var_origins => Origins#{Key => Origin}};
|
|
|
|
|
update_context(Context, Key, Value, Origin)
|
|
|
|
|
when ?origin_is_valid(Origin) ->
|
|
|
|
|
Context#{Key => Value,
|
|
|
|
|
var_origins => #{Key => Origin}}.
|
|
|
|
|
|
2019-09-03 23:28:30 +08:00
|
|
|
log_process_env() ->
|
|
|
|
|
rabbit_log_prelaunch:debug("Process environment:"),
|
|
|
|
|
lists:foreach(
|
|
|
|
|
fun({Var, Value}) ->
|
|
|
|
|
rabbit_log_prelaunch:debug(" - ~s = ~ts", [Var, Value])
|
|
|
|
|
end, lists:sort(os:list_env_vars())).
|
|
|
|
|
|
|
|
|
|
log_context(Context) ->
|
|
|
|
|
rabbit_log_prelaunch:debug("Context (based on environment variables):"),
|
|
|
|
|
lists:foreach(
|
|
|
|
|
fun(Key) ->
|
|
|
|
|
Value = maps:get(Key, Context),
|
|
|
|
|
rabbit_log_prelaunch:debug(" - ~s: ~p", [Key, Value])
|
|
|
|
|
end,
|
|
|
|
|
lists:sort(maps:keys(Context))).
|
|
|
|
|
|
|
|
|
|
context_to_app_env_vars(Context) ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
"Setting default application environment variables:"),
|
|
|
|
|
Fun = fun({App, Param, Value}) ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
" - ~s:~s = ~p", [App, Param, Value]),
|
|
|
|
|
ok = application:set_env(
|
|
|
|
|
App, Param, Value, [{persistent, true}])
|
|
|
|
|
end,
|
|
|
|
|
context_to_app_env_vars1(Context, Fun).
|
|
|
|
|
|
|
|
|
|
context_to_app_env_vars_no_logging(Context) ->
|
|
|
|
|
Fun = fun({App, Param, Value}) ->
|
|
|
|
|
ok = application:set_env(
|
|
|
|
|
App, Param, Value, [{persistent, true}])
|
|
|
|
|
end,
|
|
|
|
|
context_to_app_env_vars1(Context, Fun).
|
|
|
|
|
|
|
|
|
|
context_to_app_env_vars1(
|
|
|
|
|
#{mnesia_dir := MnesiaDir,
|
|
|
|
|
feature_flags_file := FFFile,
|
|
|
|
|
quorum_queue_dir := QuorumQueueDir,
|
|
|
|
|
plugins_path := PluginsPath,
|
|
|
|
|
plugins_expand_dir := PluginsExpandDir,
|
|
|
|
|
enabled_plugins_file := EnabledPluginsFile} = Context,
|
|
|
|
|
Fun) ->
|
|
|
|
|
lists:foreach(
|
|
|
|
|
Fun,
|
|
|
|
|
%% Those are all the application environment variables which
|
|
|
|
|
%% were historically set on the erl(1) command line in
|
|
|
|
|
%% rabbitmq-server(8).
|
|
|
|
|
[{kernel, inet_default_connect_options, [{nodelay, true}]},
|
|
|
|
|
{sasl, errlog_type, error},
|
|
|
|
|
{os_mon, start_cpu_sup, false},
|
|
|
|
|
{os_mon, start_disksup, false},
|
|
|
|
|
{os_mon, start_memsup, false},
|
|
|
|
|
{mnesia, dir, MnesiaDir},
|
|
|
|
|
{ra, data_dir, QuorumQueueDir},
|
|
|
|
|
{rabbit, feature_flags_file, FFFile},
|
|
|
|
|
{rabbit, plugins_dir, PluginsPath},
|
|
|
|
|
{rabbit, plugins_expand_dir, PluginsExpandDir},
|
|
|
|
|
{rabbit, enabled_plugins_file, EnabledPluginsFile}]),
|
|
|
|
|
|
|
|
|
|
case Context of
|
|
|
|
|
#{erlang_dist_tcp_port := DistTcpPort} ->
|
|
|
|
|
lists:foreach(
|
|
|
|
|
Fun,
|
|
|
|
|
[{kernel, inet_dist_listen_min, DistTcpPort},
|
|
|
|
|
{kernel, inet_dist_listen_max, DistTcpPort}]);
|
|
|
|
|
_ ->
|
|
|
|
|
ok
|
|
|
|
|
end,
|
|
|
|
|
case Context of
|
2020-01-21 01:38:59 +08:00
|
|
|
#{amqp_ipaddr := IpAddr,
|
|
|
|
|
amqp_tcp_port := TcpPort}
|
2019-09-03 23:28:30 +08:00
|
|
|
when IpAddr /= undefined andalso TcpPort /= undefined ->
|
|
|
|
|
Fun({rabbit, tcp_listeners, [{IpAddr, TcpPort}]});
|
|
|
|
|
_ ->
|
|
|
|
|
ok
|
|
|
|
|
end,
|
|
|
|
|
ok.
|
|
|
|
|
|
|
|
|
|
context_to_code_path(#{plugins_path := PluginsPath}) ->
|
|
|
|
|
Dirs = get_user_lib_dirs(PluginsPath),
|
2020-01-21 01:38:59 +08:00
|
|
|
code:add_pathsa(lists:reverse(Dirs)).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%% Code copied from `kernel/src/code_server.erl`.
|
|
|
|
|
%%
|
|
|
|
|
%% The goal is to mimic the behavior of the `$ERL_LIBS` environment
|
|
|
|
|
%% variable.
|
|
|
|
|
|
|
|
|
|
get_user_lib_dirs(Path) ->
|
|
|
|
|
Sep = case os:type() of
|
|
|
|
|
{win32, _} -> ";";
|
|
|
|
|
_ -> ":"
|
|
|
|
|
end,
|
|
|
|
|
SplitPath = string:lexemes(Path, Sep),
|
|
|
|
|
get_user_lib_dirs_1(SplitPath).
|
|
|
|
|
|
|
|
|
|
get_user_lib_dirs_1([Dir|DirList]) ->
|
|
|
|
|
case erl_prim_loader:list_dir(Dir) of
|
|
|
|
|
{ok, Dirs} ->
|
|
|
|
|
Paths = make_path(Dir, Dirs),
|
|
|
|
|
%% Only add paths trailing with ./ebin.
|
|
|
|
|
[P || P <- Paths, filename:basename(P) =:= "ebin"] ++
|
|
|
|
|
get_user_lib_dirs_1(DirList);
|
|
|
|
|
error ->
|
|
|
|
|
get_user_lib_dirs_1(DirList)
|
|
|
|
|
end;
|
|
|
|
|
get_user_lib_dirs_1([]) -> [].
|
|
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
%% Create the initial path.
|
|
|
|
|
%%
|
|
|
|
|
make_path(BundleDir, Bundles0) ->
|
|
|
|
|
Bundles = choose_bundles(Bundles0),
|
|
|
|
|
make_path(BundleDir, Bundles, []).
|
|
|
|
|
|
|
|
|
|
choose_bundles(Bundles) ->
|
|
|
|
|
ArchiveExt = archive_extension(),
|
|
|
|
|
Bs = lists:sort([create_bundle(B, ArchiveExt) || B <- Bundles]),
|
|
|
|
|
[FullName || {_Name,_NumVsn,FullName} <-
|
|
|
|
|
choose(lists:reverse(Bs), [], ArchiveExt)].
|
|
|
|
|
|
|
|
|
|
create_bundle(FullName, ArchiveExt) ->
|
|
|
|
|
BaseName = filename:basename(FullName, ArchiveExt),
|
|
|
|
|
case split_base(BaseName) of
|
|
|
|
|
{Name, VsnStr} ->
|
|
|
|
|
case vsn_to_num(VsnStr) of
|
|
|
|
|
{ok, VsnNum} ->
|
|
|
|
|
{Name,VsnNum,FullName};
|
|
|
|
|
false ->
|
|
|
|
|
{FullName,[0],FullName}
|
|
|
|
|
end;
|
|
|
|
|
_ ->
|
|
|
|
|
{FullName,[0],FullName}
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
%% Convert "X.Y.Z. ..." to [K, L, M| ...]
|
|
|
|
|
vsn_to_num(Vsn) ->
|
|
|
|
|
case is_vsn(Vsn) of
|
|
|
|
|
true ->
|
|
|
|
|
{ok, [list_to_integer(S) || S <- string:lexemes(Vsn, ".")]};
|
|
|
|
|
_ ->
|
|
|
|
|
false
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
is_vsn(Str) when is_list(Str) ->
|
|
|
|
|
Vsns = string:lexemes(Str, "."),
|
|
|
|
|
lists:all(fun is_numstr/1, Vsns).
|
|
|
|
|
|
|
|
|
|
is_numstr(Cs) ->
|
|
|
|
|
lists:all(fun (C) when $0 =< C, C =< $9 -> true;
|
|
|
|
|
(_) -> false
|
|
|
|
|
end, Cs).
|
|
|
|
|
|
|
|
|
|
choose([{Name,NumVsn,NewFullName}=New|Bs], Acc, ArchiveExt) ->
|
|
|
|
|
case lists:keyfind(Name, 1, Acc) of
|
|
|
|
|
{_, NV, OldFullName} when NV =:= NumVsn ->
|
|
|
|
|
case filename:extension(OldFullName) =:= ArchiveExt of
|
|
|
|
|
false ->
|
|
|
|
|
choose(Bs,Acc, ArchiveExt);
|
|
|
|
|
true ->
|
|
|
|
|
Acc2 = lists:keystore(Name, 1, Acc, New),
|
|
|
|
|
choose(Bs,Acc2, ArchiveExt)
|
|
|
|
|
end;
|
|
|
|
|
{_, _, _} ->
|
|
|
|
|
choose(Bs,Acc, ArchiveExt);
|
|
|
|
|
false ->
|
|
|
|
|
choose(Bs,[{Name,NumVsn,NewFullName}|Acc], ArchiveExt)
|
|
|
|
|
end;
|
|
|
|
|
choose([],Acc, _ArchiveExt) ->
|
|
|
|
|
Acc.
|
|
|
|
|
|
|
|
|
|
make_path(_, [], Res) ->
|
|
|
|
|
Res;
|
|
|
|
|
make_path(BundleDir, [Bundle|Tail], Res) ->
|
|
|
|
|
Dir = filename:append(BundleDir, Bundle),
|
|
|
|
|
Ebin = filename:append(Dir, "ebin"),
|
|
|
|
|
%% First try with /ebin
|
|
|
|
|
case is_dir(Ebin) of
|
|
|
|
|
true ->
|
|
|
|
|
make_path(BundleDir, Tail, [Ebin|Res]);
|
|
|
|
|
false ->
|
|
|
|
|
%% Second try with archive
|
|
|
|
|
Ext = archive_extension(),
|
|
|
|
|
Base = filename:basename(Bundle, Ext),
|
|
|
|
|
Ebin2 = filename:join([BundleDir, Base ++ Ext, Base, "ebin"]),
|
|
|
|
|
Ebins =
|
|
|
|
|
case split_base(Base) of
|
|
|
|
|
{AppName,_} ->
|
|
|
|
|
Ebin3 = filename:join([BundleDir, Base ++ Ext,
|
|
|
|
|
AppName, "ebin"]),
|
|
|
|
|
[Ebin3, Ebin2, Dir];
|
|
|
|
|
_ ->
|
|
|
|
|
[Ebin2, Dir]
|
|
|
|
|
end,
|
|
|
|
|
case try_ebin_dirs(Ebins) of
|
|
|
|
|
{ok,FoundEbin} ->
|
|
|
|
|
make_path(BundleDir, Tail, [FoundEbin|Res]);
|
|
|
|
|
error ->
|
|
|
|
|
make_path(BundleDir, Tail, Res)
|
|
|
|
|
end
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
try_ebin_dirs([Ebin|Ebins]) ->
|
|
|
|
|
case is_dir(Ebin) of
|
|
|
|
|
true -> {ok,Ebin};
|
|
|
|
|
false -> try_ebin_dirs(Ebins)
|
|
|
|
|
end;
|
|
|
|
|
try_ebin_dirs([]) ->
|
|
|
|
|
error.
|
|
|
|
|
|
|
|
|
|
split_base(BaseName) ->
|
|
|
|
|
case string:lexemes(BaseName, "-") of
|
|
|
|
|
[_, _|_] = Toks ->
|
|
|
|
|
Vsn = lists:last(Toks),
|
|
|
|
|
AllButLast = lists:droplast(Toks),
|
|
|
|
|
{string:join(AllButLast, "-"),Vsn};
|
|
|
|
|
[_|_] ->
|
|
|
|
|
BaseName
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
is_dir(Path) ->
|
|
|
|
|
case erl_prim_loader:read_file_info(Path) of
|
|
|
|
|
{ok,#file_info{type=directory}} -> true;
|
|
|
|
|
_ -> false
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
archive_extension() ->
|
|
|
|
|
init:archive_extension().
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_NODENAME
|
|
|
|
|
%% Erlang node name.
|
|
|
|
|
%% Default: rabbit@<hostname>
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_USE_LONGNAME
|
|
|
|
|
%% Flag indicating if long Erlang node names should be used instead
|
|
|
|
|
%% of short ones.
|
|
|
|
|
%% Default: unset (use short names)
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
nodename_type(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_USE_LONGNAME") of
|
|
|
|
|
false ->
|
|
|
|
|
update_context(Context, nodename_type, shortnames, default);
|
|
|
|
|
Value ->
|
|
|
|
|
NameType = case value_is_yes(Value) of
|
|
|
|
|
true -> longnames;
|
|
|
|
|
false -> shortnames
|
|
|
|
|
end,
|
|
|
|
|
update_context(Context, nodename_type, NameType, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
nodename(#{nodename_type := NameType} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
LongHostname = net_adm:localhost(),
|
|
|
|
|
ShortHostname = re:replace(LongHostname, "\\..*$", "", [{return, list}]),
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_NODENAME") of
|
|
|
|
|
false when NameType =:= shortnames ->
|
2020-01-21 01:38:59 +08:00
|
|
|
Nodename = rabbit_nodes_common:make({"rabbit", ShortHostname}),
|
|
|
|
|
update_context(Context, nodename, Nodename, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
false when NameType =:= longnames ->
|
2020-01-21 01:38:59 +08:00
|
|
|
Nodename = rabbit_nodes_common:make({"rabbit", LongHostname}),
|
|
|
|
|
update_context(Context, nodename, Nodename, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
Value ->
|
2020-01-21 01:38:59 +08:00
|
|
|
Nodename = case string:find(Value, "@") of
|
|
|
|
|
nomatch when NameType =:= shortnames ->
|
|
|
|
|
rabbit_nodes_common:make({Value, ShortHostname});
|
|
|
|
|
nomatch when NameType =:= longnames ->
|
|
|
|
|
rabbit_nodes_common:make({Value, LongHostname});
|
|
|
|
|
_ ->
|
|
|
|
|
rabbit_nodes_common:make(Value)
|
|
|
|
|
end,
|
|
|
|
|
update_context(Context, nodename, Nodename, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
split_nodename(#{nodename := Nodename} = Context) ->
|
|
|
|
|
update_context(Context,
|
|
|
|
|
split_nodename, rabbit_nodes_common:parts(Nodename)).
|
|
|
|
|
|
2019-09-03 23:28:30 +08:00
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_CONFIG_FILE
|
|
|
|
|
%% Main configuration file.
|
|
|
|
|
%% Extension is optional. `.config` for the old rlang-term-based
|
|
|
|
|
%% format, `.conf` for the new Cuttlefish-based format.
|
|
|
|
|
%% Default: (Unix) ${SYS_PREFIX}/etc/rabbitmq/rabbitmq
|
|
|
|
|
%% (Windows) ${RABBITMQ_BASE}\rabbitmq
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_ADVANCED_CONFIG_FILE
|
|
|
|
|
%% Advanced configuration file.
|
|
|
|
|
%% Erlang-term-based format with a `.config` extension.
|
|
|
|
|
%% Default: (Unix) ${SYS_PREFIX}/etc/rabbitmq/advanced.config
|
|
|
|
|
%% (Windows) ${RABBITMQ_BASE}\advanced.config
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
config_base_dir(#{os_type := {unix, _},
|
|
|
|
|
sys_prefix := SysPrefix} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
Dir = filename:join([SysPrefix, "etc", "rabbitmq"]),
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, config_base_dir, Dir);
|
|
|
|
|
config_base_dir(#{os_type := {win32, _},
|
|
|
|
|
rabbitmq_base := Dir} = Context) ->
|
|
|
|
|
update_context(Context, config_base_dir, Dir).
|
|
|
|
|
|
|
|
|
|
main_config_file(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_CONFIG_FILE") of
|
|
|
|
|
false ->
|
|
|
|
|
File = get_default_main_config_file(Context),
|
|
|
|
|
update_context(Context, main_config_file, File, default);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, main_config_file, File, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
get_default_main_config_file(#{config_base_dir := ConfigBaseDir}) ->
|
|
|
|
|
filename:join(ConfigBaseDir, "rabbitmq").
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
advanced_config_file(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_ADVANCED_CONFIG_FILE") of
|
|
|
|
|
false ->
|
|
|
|
|
File = get_default_advanced_config_file(Context),
|
|
|
|
|
update_context(Context, advanced_config_file, File, default);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, advanced_config_file, File, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
get_default_advanced_config_file(#{config_base_dir := ConfigBaseDir}) ->
|
|
|
|
|
filename:join(ConfigBaseDir, "advanced.config").
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_LOG_BASE
|
|
|
|
|
%% Directory to write log files
|
|
|
|
|
%% Default: (Unix) ${SYS_PREFIX}/var/log/rabbitmq
|
|
|
|
|
%% (Windows) ${RABBITMQ_BASE}\log
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_LOGS
|
|
|
|
|
%% Main log file
|
|
|
|
|
%% Default: ${RABBITMQ_LOG_BASE}/${RABBITMQ_NODENAME}.log
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_UPDATE_LOG
|
|
|
|
|
%% Upgrade-procesure-specific log file
|
|
|
|
|
%% Default: ${RABBITMQ_LOG_BASE}/${RABBITMQ_NODENAME}_upgrade.log
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_LOG
|
|
|
|
|
%% Log level; overrides the configuration file value
|
|
|
|
|
%% Default: (undefined)
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_DBG
|
|
|
|
|
%% List of `module`, `module:function` or `module:function/arity`
|
|
|
|
|
%% to watch with dbg.
|
|
|
|
|
%% Default: (undefined)
|
|
|
|
|
|
|
|
|
|
log_levels(Context) ->
|
2020-01-21 01:38:59 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_LOG") of
|
|
|
|
|
false ->
|
|
|
|
|
update_context(Context, log_levels, undefined, default);
|
|
|
|
|
Value ->
|
|
|
|
|
LogLevels = parse_log_levels(string:lexemes(Value, ","), #{}),
|
|
|
|
|
update_context(Context, log_levels, LogLevels, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels([CategoryValue | Rest], Result) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case string:lexemes(CategoryValue, "=") of
|
|
|
|
|
["+color"] ->
|
|
|
|
|
Result1 = Result#{color => true},
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels(Rest, Result1);
|
2019-09-03 23:28:30 +08:00
|
|
|
["-color"] ->
|
|
|
|
|
Result1 = Result#{color => false},
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels(Rest, Result1);
|
2019-09-03 23:28:30 +08:00
|
|
|
[CategoryOrLevel] ->
|
|
|
|
|
case parse_level(CategoryOrLevel) of
|
|
|
|
|
undefined ->
|
|
|
|
|
Result1 = Result#{CategoryOrLevel => info},
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels(Rest, Result1);
|
2019-09-03 23:28:30 +08:00
|
|
|
Level ->
|
|
|
|
|
Result1 = Result#{global => Level},
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels(Rest, Result1)
|
2019-09-03 23:28:30 +08:00
|
|
|
end;
|
|
|
|
|
[Category, Level0] ->
|
|
|
|
|
case parse_level(Level0) of
|
|
|
|
|
undefined ->
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels(Rest, Result);
|
2019-09-03 23:28:30 +08:00
|
|
|
Level ->
|
|
|
|
|
Result1 = Result#{Category => Level},
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels(Rest, Result1)
|
2019-09-03 23:28:30 +08:00
|
|
|
end
|
|
|
|
|
end;
|
2020-01-21 01:38:59 +08:00
|
|
|
parse_log_levels([], Result) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
Result.
|
|
|
|
|
|
|
|
|
|
parse_level("debug") -> debug;
|
|
|
|
|
parse_level("info") -> info;
|
|
|
|
|
parse_level("notice") -> notice;
|
|
|
|
|
parse_level("warning") -> warning;
|
|
|
|
|
parse_level("error") -> error;
|
|
|
|
|
parse_level("critical") -> critical;
|
|
|
|
|
parse_level("alert") -> alert;
|
|
|
|
|
parse_level("emergency") -> emergency;
|
|
|
|
|
parse_level("none") -> none;
|
|
|
|
|
parse_level(_) -> undefined.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
log_base_dir(#{os_type := OSType} = Context) ->
|
|
|
|
|
case {get_prefixed_env_var("RABBITMQ_LOG_BASE"), OSType} of
|
|
|
|
|
{false, {unix, _}} ->
|
|
|
|
|
#{sys_prefix := SysPrefix} = Context,
|
|
|
|
|
Dir = filename:join([SysPrefix, "var", "log", "rabbitmq"]),
|
|
|
|
|
update_context(Context, log_base_dir, Dir, default);
|
|
|
|
|
{false, {win32, _}} ->
|
|
|
|
|
#{rabbitmq_base := RabbitmqBase} = Context,
|
|
|
|
|
Dir = filename:join([RabbitmqBase, "log"]),
|
|
|
|
|
update_context(Context, log_base_dir, Dir, default);
|
|
|
|
|
{Value, _} ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, log_base_dir, Dir, environment)
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
main_log_file(#{nodename := Nodename,
|
|
|
|
|
log_base_dir := LogBaseDir} = Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_LOGS") of
|
|
|
|
|
false ->
|
|
|
|
|
File= filename:join(LogBaseDir,
|
|
|
|
|
atom_to_list(Nodename) ++ ".log"),
|
|
|
|
|
update_context(Context, main_log_file, File, default);
|
|
|
|
|
"-" ->
|
|
|
|
|
update_context(Context, main_log_file, "-", environment);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, main_log_file, File, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
upgrade_log_file(#{nodename := Nodename,
|
|
|
|
|
log_base_dir := LogBaseDir} = Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_UPGRADE_LOG") of
|
|
|
|
|
false ->
|
|
|
|
|
File = filename:join(LogBaseDir,
|
|
|
|
|
atom_to_list(Nodename) ++ "_upgrade.log"),
|
|
|
|
|
update_context(Context, upgrade_log_file, File, default);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, upgrade_log_file, File, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
dbg_config() ->
|
|
|
|
|
{Mods, Output} = get_dbg_config(),
|
|
|
|
|
#{dbg_output => Output,
|
|
|
|
|
dbg_mods => Mods}.
|
|
|
|
|
|
|
|
|
|
dbg_config(Context) ->
|
|
|
|
|
DbgContext = dbg_config(),
|
|
|
|
|
maps:merge(Context, DbgContext).
|
|
|
|
|
|
|
|
|
|
get_dbg_config() ->
|
|
|
|
|
Output = stdout,
|
|
|
|
|
DbgValue = get_prefixed_env_var("RABBITMQ_DBG"),
|
|
|
|
|
case DbgValue of
|
|
|
|
|
false -> {[], Output};
|
|
|
|
|
_ -> get_dbg_config1(string:lexemes(DbgValue, ","), [], Output)
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
get_dbg_config1(["=" ++ Filename | Rest], Mods, _) ->
|
|
|
|
|
get_dbg_config1(Rest, Mods, Filename);
|
|
|
|
|
get_dbg_config1([SpecValue | Rest], Mods, Output) ->
|
|
|
|
|
Pattern = "([^:]+)(?::([^/]+)(?:/([0-9]+))?)?",
|
|
|
|
|
Options = [{capture, all_but_first, list}],
|
|
|
|
|
Mods1 = case re:run(SpecValue, Pattern, Options) of
|
|
|
|
|
{match, [M, F, A]} ->
|
|
|
|
|
Entry = {list_to_atom(M),
|
|
|
|
|
list_to_atom(F),
|
|
|
|
|
list_to_integer(A)},
|
|
|
|
|
[Entry | Mods];
|
|
|
|
|
{match, [M, F]} ->
|
|
|
|
|
Entry = {list_to_atom(M),
|
|
|
|
|
list_to_atom(F),
|
|
|
|
|
'_'},
|
|
|
|
|
[Entry | Mods];
|
|
|
|
|
{match, [M]} ->
|
|
|
|
|
Entry = {list_to_atom(M),
|
|
|
|
|
'_',
|
|
|
|
|
'_'},
|
|
|
|
|
[Entry | Mods];
|
|
|
|
|
nomatch ->
|
|
|
|
|
Mods
|
|
|
|
|
end,
|
|
|
|
|
get_dbg_config1(Rest, Mods1, Output);
|
|
|
|
|
get_dbg_config1([], Mods, Output) ->
|
|
|
|
|
{lists:reverse(Mods), Output}.
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_MNESIA_BASE
|
|
|
|
|
%% Directory where to create Mnesia directory.
|
|
|
|
|
%% Default: (Unix) ${SYS_PREFIX}/var/lib/rabbitmq/mnesia
|
|
|
|
|
%% (Windows) ${RABBITMQ_BASE}/db
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_MNESIA_DIR
|
|
|
|
|
%% Directory where to put Mnesia data.
|
|
|
|
|
%% Default: (Unix) ${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}
|
|
|
|
|
%% (Windows) ${RABBITMQ_MNESIA_BASE}\${RABBITMQ_NODENAME}-mnesia
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_base_dir(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_MNESIA_BASE") of
|
|
|
|
|
false when Remote =:= offline ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, mnesia_base_dir, undefined, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
false ->
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_base_dir_from_node(Context);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, mnesia_base_dir, Dir, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end;
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_base_dir(Context) ->
|
|
|
|
|
mnesia_base_dir_from_env(Context).
|
|
|
|
|
|
|
|
|
|
mnesia_base_dir_from_env(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_MNESIA_BASE") of
|
|
|
|
|
false ->
|
|
|
|
|
Dir = get_default_mnesia_base_dir(Context),
|
|
|
|
|
update_context(Context, mnesia_base_dir, Dir, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, mnesia_base_dir, Dir, environment)
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
mnesia_base_dir_from_node(Context) ->
|
|
|
|
|
%% This variable is used to compute other variables only, we
|
|
|
|
|
%% don't need to know what a remote node used initially. Only the
|
|
|
|
|
%% variables based on it are relevant.
|
|
|
|
|
update_context(Context, mnesia_base_dir, undefined, default).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
get_default_mnesia_base_dir(#{data_dir := DataDir} = Context) ->
|
|
|
|
|
Basename = case Context of
|
|
|
|
|
#{os_type := {unix, _}} -> "mnesia";
|
|
|
|
|
#{os_type := {win32, _}} -> "db"
|
|
|
|
|
end,
|
|
|
|
|
filename:join(DataDir, Basename).
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_dir(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_MNESIA_DIR") of
|
|
|
|
|
false when Remote =:= offline ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, mnesia_dir, undefined, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
false ->
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_dir_from_node(Context);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, mnesia_dir, Dir, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end;
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_dir(Context) ->
|
|
|
|
|
mnesia_dir_from_env(Context).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_dir_from_env(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_MNESIA_DIR") of
|
|
|
|
|
false ->
|
|
|
|
|
Dir = get_default_mnesia_dir(Context),
|
|
|
|
|
update_context(Context, mnesia_dir, Dir, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, mnesia_dir, Dir, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
mnesia_dir_from_node(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
Ret = query_remote(Remote, application, get_env, [mnesia, dir]),
|
|
|
|
|
case Ret of
|
|
|
|
|
{ok, undefined} ->
|
|
|
|
|
throw({query, Remote, {mnesia, dir, undefined}});
|
2020-01-21 01:38:59 +08:00
|
|
|
{ok, {ok, Value}} ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, mnesia_dir, Dir, remote_node);
|
2019-09-03 23:28:30 +08:00
|
|
|
{badrpc, nodedown} ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, mnesia_dir, undefined, default)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
get_default_mnesia_dir(#{os_type := {unix, _},
|
|
|
|
|
nodename := Nodename,
|
|
|
|
|
mnesia_base_dir := MnesiaBaseDir})
|
|
|
|
|
when MnesiaBaseDir =/= undefined ->
|
2019-09-03 23:28:30 +08:00
|
|
|
filename:join(MnesiaBaseDir, atom_to_list(Nodename));
|
2020-01-21 01:38:59 +08:00
|
|
|
get_default_mnesia_dir(#{os_type := {win32, _},
|
|
|
|
|
nodename := Nodename,
|
|
|
|
|
mnesia_base_dir := MnesiaBaseDir})
|
|
|
|
|
when MnesiaBaseDir =/= undefined ->
|
2019-09-03 23:28:30 +08:00
|
|
|
filename:join(MnesiaBaseDir, atom_to_list(Nodename) ++ "-mnesia").
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_QUORUM_DIR
|
|
|
|
|
%% Directory where to store Ra state for quorum queues.
|
|
|
|
|
%% Default: ${RABBITMQ_MNESIA_DIR}/quorum
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
quorum_queue_dir(#{mnesia_dir := MnesiaDir} = Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_QUORUM_DIR") of
|
|
|
|
|
false when MnesiaDir =/= undefined ->
|
|
|
|
|
Dir = filename:join(MnesiaDir, "quorum"),
|
|
|
|
|
update_context(Context, quorum_queue_dir, Dir, default);
|
|
|
|
|
false when MnesiaDir =:= undefined ->
|
|
|
|
|
update_context(Context, quorum_queue_dir, undefined, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, quorum_queue_dir, Dir, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_PID_FILE
|
|
|
|
|
%% File used to write the Erlang VM OS PID.
|
|
|
|
|
%% Default: ${RABBITMQ_MNESIA_DIR}.pid
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_KEEP_PID_FILE_ON_EXIT
|
|
|
|
|
%% Whether to keep or remove the PID file on Erlang VM exit.
|
|
|
|
|
%% Default: true
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
pid_file(#{mnesia_base_dir := MnesiaBaseDir,
|
|
|
|
|
nodename := Nodename} = Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_PID_FILE") of
|
|
|
|
|
false when MnesiaBaseDir =/= undefined ->
|
|
|
|
|
File = filename:join(MnesiaBaseDir,
|
|
|
|
|
atom_to_list(Nodename) ++ ".pid"),
|
|
|
|
|
update_context(Context, pid_file, File, default);
|
|
|
|
|
false when MnesiaBaseDir =:= undefined ->
|
|
|
|
|
update_context(Context, pid_file, undefined, default);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, pid_file, File, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
keep_pid_file_on_exit(Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_KEEP_PID_FILE_ON_EXIT") of
|
2020-01-21 01:38:59 +08:00
|
|
|
false ->
|
|
|
|
|
update_context(Context, keep_pid_file_on_exit, false, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Keep = value_is_yes(Value),
|
|
|
|
|
update_context(Context, keep_pid_file_on_exit, Keep, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_FEATURE_FLAGS_FILE
|
|
|
|
|
%% File used to store enabled feature flags.
|
|
|
|
|
%% Default: ${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-feature_flags
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
feature_flags_file(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_FEATURE_FLAGS_FILE") of
|
|
|
|
|
false when Remote =:= offline ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, feature_flags_file, undefined, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
false ->
|
2020-01-21 01:38:59 +08:00
|
|
|
feature_flags_file_from_node(Context);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, feature_flags_file, File, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end;
|
2020-01-21 01:38:59 +08:00
|
|
|
feature_flags_file(Context) ->
|
|
|
|
|
feature_flags_file_from_env(Context).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
feature_flags_file_from_env(#{mnesia_base_dir := MnesiaBaseDir,
|
|
|
|
|
nodename := Nodename} = Context) ->
|
|
|
|
|
case get_env_var("RABBITMQ_FEATURE_FLAGS_FILE") of
|
|
|
|
|
false ->
|
|
|
|
|
File = filename:join(MnesiaBaseDir,
|
|
|
|
|
atom_to_list(Nodename) ++ "-feature_flags"),
|
|
|
|
|
update_context(Context, feature_flags_file, File, default);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, feature_flags_file, File, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
feature_flags_file_from_node(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
Ret = query_remote(Remote,
|
|
|
|
|
application, get_env, [rabbit, feature_flags_file]),
|
|
|
|
|
case Ret of
|
|
|
|
|
{ok, undefined} ->
|
|
|
|
|
throw({query, Remote, {rabbit, feature_flags_file, undefined}});
|
2020-01-21 01:38:59 +08:00
|
|
|
{ok, {ok, Value}} ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, feature_flags_file, File, remote_node);
|
2019-09-03 23:28:30 +08:00
|
|
|
{badrpc, nodedown} ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, feature_flags_file, undefined, default)
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
forced_feature_flags_on_init(Context) ->
|
|
|
|
|
Value = get_prefixed_env_var("RABBITMQ_FEATURE_FLAGS",
|
|
|
|
|
[keep_empty_string_as_is]),
|
|
|
|
|
case Value of
|
|
|
|
|
false ->
|
|
|
|
|
%% get_prefixed_env_var() considers an empty string
|
|
|
|
|
%% is the same as an undefined environment variable.
|
|
|
|
|
update_context(Context,
|
|
|
|
|
forced_feature_flags_on_init, undefined, default);
|
|
|
|
|
_ ->
|
|
|
|
|
Flags = [list_to_atom(V) || V <- string:lexemes(Value, ",")],
|
|
|
|
|
update_context(Context,
|
|
|
|
|
forced_feature_flags_on_init, Flags, environment)
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
log_feature_flags_registry(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_LOG_FF_REGISTRY") of
|
|
|
|
|
false ->
|
|
|
|
|
update_context(Context,
|
|
|
|
|
log_feature_flags_registry, false, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Log = value_is_yes(Value),
|
|
|
|
|
update_context(Context,
|
|
|
|
|
log_feature_flags_registry, Log, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_PLUGINS_DIR
|
|
|
|
|
%% List of directories where to look for plugins.
|
|
|
|
|
%% Directories are separated by:
|
|
|
|
|
%% ':' on Unix
|
|
|
|
|
%% ';' on Windows
|
|
|
|
|
%% Default: ${RABBITMQ_HOME}/plugins
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_PLUGINS_EXPAND_DIR
|
|
|
|
|
%% Directory where to expand plugin archives.
|
|
|
|
|
%% Default: ${RABBITMQ_MNESIA_BASE}/${RABBITMQ_NODENAME}-plugins-expand
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_ENABLED_PLUGINS_FILE
|
|
|
|
|
%% File where the list of enabled plugins is stored.
|
|
|
|
|
%% Default: (Unix) ${SYS_PREFIX}/etc/rabbitmq/enabled_plugins
|
|
|
|
|
%% (Windows) ${RABBITMQ_BASE}\enabled_plugins
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_ENABLED_PLUGINS
|
|
|
|
|
%% List of plugins to enable on startup.
|
|
|
|
|
%% Values are:
|
|
|
|
|
%% "ALL" to enable all plugins
|
2020-01-24 19:54:43 +08:00
|
|
|
%% "" to enable no plugin
|
2019-09-03 23:28:30 +08:00
|
|
|
%% a list of plugin names, separated by a coma (',')
|
|
|
|
|
%% Default: Empty (i.e. use ${RABBITMQ_ENABLED_PLUGINS_FILE})
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
plugins_path(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_PLUGINS_DIR") of
|
|
|
|
|
false when Remote =:= offline ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, plugins_path, undefined, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
false ->
|
2020-01-21 01:38:59 +08:00
|
|
|
plugins_path_from_node(Context);
|
2019-09-03 23:28:30 +08:00
|
|
|
Path ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, plugins_path, Path, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end;
|
2020-01-21 01:38:59 +08:00
|
|
|
plugins_path(Context) ->
|
|
|
|
|
plugins_path_from_env(Context).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
plugins_path_from_env(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_PLUGINS_DIR") of
|
|
|
|
|
false ->
|
|
|
|
|
Path = get_default_plugins_path_from_env(Context),
|
|
|
|
|
update_context(Context, plugins_path, Path, default);
|
|
|
|
|
Path ->
|
|
|
|
|
update_context(Context, plugins_path, Path, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
plugins_path_from_node(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
Ret = query_remote(Remote, application, get_env, [rabbit, plugins_dir]),
|
|
|
|
|
case Ret of
|
|
|
|
|
{ok, undefined} ->
|
|
|
|
|
throw({query, Remote, {rabbit, plugins_dir, undefined}});
|
|
|
|
|
{ok, {ok, Path}} ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, plugins_path, Path, remote_node);
|
2019-09-03 23:28:30 +08:00
|
|
|
{badrpc, nodedown} ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, plugins_path, undefined, default)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
get_default_plugins_path(#{from_remote_node := offline}) ->
|
|
|
|
|
undefined;
|
|
|
|
|
get_default_plugins_path(#{from_remote_node := Remote}) ->
|
|
|
|
|
get_default_plugins_path_from_node(Remote);
|
|
|
|
|
get_default_plugins_path(Context) ->
|
|
|
|
|
get_default_plugins_path_from_env(Context).
|
|
|
|
|
|
|
|
|
|
get_default_plugins_path_from_env(#{os_type := OSType}) ->
|
|
|
|
|
ThisModDir = this_module_dir(),
|
2020-01-21 21:50:07 +08:00
|
|
|
PluginsDir = rabbit_common_mod_location_to_plugins_dir(ThisModDir),
|
2019-09-03 23:28:30 +08:00
|
|
|
case {OSType, PluginsDir} of
|
|
|
|
|
{{unix, _}, "/usr/lib/rabbitmq/" ++ _} ->
|
|
|
|
|
UserPluginsDir = filename:join(
|
|
|
|
|
["/", "usr", "lib", "rabbitmq", "plugins"]),
|
|
|
|
|
UserPluginsDir ++ ":" ++ PluginsDir;
|
|
|
|
|
_ ->
|
|
|
|
|
PluginsDir
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
get_default_plugins_path_from_node(Remote) ->
|
2020-01-21 21:50:07 +08:00
|
|
|
Ret = query_remote(Remote, code, where_is_file, ["rabbit_common.app"]),
|
2019-09-03 23:28:30 +08:00
|
|
|
case Ret of
|
2020-01-21 21:50:07 +08:00
|
|
|
{ok, non_existing = Error} ->
|
|
|
|
|
throw({query, Remote, {code, where_is_file, Error}});
|
2019-09-03 23:28:30 +08:00
|
|
|
{ok, Path} ->
|
2020-01-21 21:50:07 +08:00
|
|
|
rabbit_common_mod_location_to_plugins_dir(filename:dirname(Path));
|
2019-09-03 23:28:30 +08:00
|
|
|
{badrpc, nodedown} ->
|
|
|
|
|
undefined
|
|
|
|
|
end.
|
|
|
|
|
|
2020-01-21 21:50:07 +08:00
|
|
|
rabbit_common_mod_location_to_plugins_dir(ModDir) ->
|
|
|
|
|
case filename:basename(ModDir) of
|
|
|
|
|
"ebin" ->
|
|
|
|
|
case filelib:is_dir(ModDir) of
|
|
|
|
|
false ->
|
|
|
|
|
%% rabbit_common in the plugin's .ez archive.
|
|
|
|
|
filename:dirname(
|
|
|
|
|
filename:dirname(
|
|
|
|
|
filename:dirname(ModDir)));
|
|
|
|
|
true ->
|
|
|
|
|
%% rabbit_common in the plugin's directory.
|
|
|
|
|
filename:dirname(
|
|
|
|
|
filename:dirname(ModDir))
|
|
|
|
|
end;
|
|
|
|
|
_ ->
|
|
|
|
|
%% rabbit_common in the CLI escript.
|
|
|
|
|
filename:join(
|
|
|
|
|
filename:dirname(
|
|
|
|
|
filename:dirname(ModDir)),
|
|
|
|
|
"plugins")
|
|
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
plugins_expand_dir(#{mnesia_base_dir := MnesiaBaseDir,
|
|
|
|
|
nodename := Nodename} = Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_PLUGINS_EXPAND_DIR") of
|
|
|
|
|
false when MnesiaBaseDir =/= undefined ->
|
|
|
|
|
Dir = filename:join(
|
|
|
|
|
MnesiaBaseDir,
|
|
|
|
|
atom_to_list(Nodename) ++ "-plugins-expand"),
|
|
|
|
|
update_context(Context, plugins_expand_dir, Dir, default);
|
|
|
|
|
false when MnesiaBaseDir =:= undefined ->
|
|
|
|
|
update_context(Context, plugins_expand_dir, undefined, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, plugins_expand_dir, Dir, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
enabled_plugins_file(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_ENABLED_PLUGINS_FILE") of
|
|
|
|
|
false when Remote =:= offline ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, enabled_plugins_file, undefined, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
false ->
|
2020-01-21 01:38:59 +08:00
|
|
|
enabled_plugins_file_from_node(Context);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, enabled_plugins_file, File, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end;
|
2020-01-21 01:38:59 +08:00
|
|
|
enabled_plugins_file(Context) ->
|
|
|
|
|
enabled_plugins_file_from_env(Context).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
enabled_plugins_file_from_env(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_ENABLED_PLUGINS_FILE") of
|
|
|
|
|
false ->
|
|
|
|
|
File = get_default_enabled_plugins_file(Context),
|
|
|
|
|
update_context(Context, enabled_plugins_file, File, default);
|
|
|
|
|
Value ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, enabled_plugins_file, File, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
get_default_enabled_plugins_file(#{config_base_dir := ConfigBaseDir}) ->
|
|
|
|
|
filename:join(ConfigBaseDir, "enabled_plugins").
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
enabled_plugins_file_from_node(#{from_remote_node := Remote} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
Ret = query_remote(Remote,
|
|
|
|
|
application, get_env, [rabbit, enabled_plugins_file]),
|
|
|
|
|
case Ret of
|
|
|
|
|
{ok, undefined} ->
|
|
|
|
|
throw({query, Remote, {rabbit, enabled_plugins_file, undefined}});
|
2020-01-21 01:38:59 +08:00
|
|
|
{ok, {ok, Value}} ->
|
|
|
|
|
File = normalize_path(Value),
|
|
|
|
|
update_context(Context, enabled_plugins_file, File, remote_node);
|
2019-09-03 23:28:30 +08:00
|
|
|
{badrpc, nodedown} ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, enabled_plugins_file, undefined, default)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
enabled_plugins(Context) ->
|
2020-01-24 19:54:43 +08:00
|
|
|
Value = get_prefixed_env_var(
|
|
|
|
|
"RABBITMQ_ENABLED_PLUGINS",
|
|
|
|
|
[keep_empty_string_as_is]),
|
|
|
|
|
case Value of
|
2020-01-21 01:38:59 +08:00
|
|
|
false ->
|
|
|
|
|
update_context(Context, enabled_plugins, undefined, default);
|
|
|
|
|
"ALL" ->
|
|
|
|
|
update_context(Context, enabled_plugins, all, environment);
|
2020-01-24 19:54:43 +08:00
|
|
|
"" ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, enabled_plugins, [], environment);
|
2020-01-24 19:54:43 +08:00
|
|
|
_ ->
|
2020-01-21 01:38:59 +08:00
|
|
|
Plugins = [list_to_atom(P) || P <- string:lexemes(Value, ",")],
|
|
|
|
|
update_context(Context, enabled_plugins, Plugins, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_NODE_IP_ADDRESS
|
|
|
|
|
%% AMQP TCP IP address to listen on
|
|
|
|
|
%% Default: unset (i.e. listen on all interfaces)
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_NODE_PORT
|
|
|
|
|
%% AMQP TCP port.
|
|
|
|
|
%% Default: 5672
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_DIST_PORT
|
|
|
|
|
%% Erlang distribution TCP port.
|
|
|
|
|
%% Default: ${RABBITMQ_NODE_PORT} + 20000
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
amqp_ipaddr(Context) ->
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_NODE_IP_ADDRESS") of
|
|
|
|
|
false ->
|
|
|
|
|
update_context(Context, amqp_ipaddr, "auto", default);
|
|
|
|
|
Value ->
|
|
|
|
|
update_context(Context, amqp_ipaddr, Value, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
amqp_tcp_port(Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_NODE_PORT") of
|
|
|
|
|
false ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, amqp_tcp_port, 5672, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
TcpPortStr ->
|
|
|
|
|
try
|
2020-01-21 01:38:59 +08:00
|
|
|
TcpPort = erlang:list_to_integer(TcpPortStr),
|
|
|
|
|
update_context(Context, amqp_tcp_port, TcpPort, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
catch
|
|
|
|
|
_:badarg ->
|
|
|
|
|
rabbit_log_prelaunch:error(
|
|
|
|
|
"Invalid value for $RABBITMQ_NODE_PORT: ~p",
|
|
|
|
|
[TcpPortStr]),
|
|
|
|
|
throw({exit, ex_config})
|
|
|
|
|
end
|
|
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
erlang_dist_tcp_port(#{amqp_tcp_port := AmqpTcpPort} = Context) ->
|
2019-09-03 23:28:30 +08:00
|
|
|
case get_prefixed_env_var("RABBITMQ_DIST_PORT") of
|
|
|
|
|
false ->
|
2020-01-21 01:38:59 +08:00
|
|
|
TcpPort = AmqpTcpPort + 20000,
|
|
|
|
|
update_context(Context, erlang_dist_tcp_port, TcpPort, default);
|
2019-09-03 23:28:30 +08:00
|
|
|
TcpPortStr ->
|
|
|
|
|
try
|
2020-01-21 01:38:59 +08:00
|
|
|
TcpPort = erlang:list_to_integer(TcpPortStr),
|
|
|
|
|
update_context(Context,
|
|
|
|
|
erlang_dist_tcp_port, TcpPort, environment)
|
2019-09-03 23:28:30 +08:00
|
|
|
catch
|
|
|
|
|
_:badarg ->
|
|
|
|
|
rabbit_log_prelaunch:error(
|
|
|
|
|
"Invalid value for $RABBITMQ_DIST_PORT: ~p",
|
|
|
|
|
[TcpPortStr]),
|
|
|
|
|
throw({exit, ex_config})
|
|
|
|
|
end
|
|
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% SYS_PREFIX [Unix only]
|
|
|
|
|
%% Default: ""
|
2019-09-03 23:28:30 +08:00
|
|
|
%%
|
2020-01-21 01:38:59 +08:00
|
|
|
%% RABBITMQ_BASE [Windows only]
|
|
|
|
|
%% Directory where to put RabbitMQ data.
|
|
|
|
|
%% Default: !APPDATA!\RabbitMQ
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
sys_prefix(#{os_type := {unix, _}} = Context) ->
|
|
|
|
|
case get_env_var("SYS_PREFIX") of
|
|
|
|
|
false ->
|
|
|
|
|
update_context(Context, sys_prefix, "", default);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, sys_prefix, Dir, environment)
|
|
|
|
|
end;
|
|
|
|
|
sys_prefix(Context) ->
|
|
|
|
|
Context.
|
|
|
|
|
|
|
|
|
|
rabbitmq_base(#{os_type := {win32, _}} = Context) ->
|
|
|
|
|
case get_env_var("RABBITMQ_BASE") of
|
|
|
|
|
false ->
|
|
|
|
|
AppData = normalize_path(get_env_var("APPDATA")),
|
|
|
|
|
Dir = filename:join(AppData, "RabbitMQ"),
|
|
|
|
|
update_context(Context, rabbitmq_base, Dir, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, rabbitmq_base, Dir, environment)
|
|
|
|
|
end;
|
|
|
|
|
rabbitmq_base(Context) ->
|
|
|
|
|
Context.
|
|
|
|
|
|
|
|
|
|
data_dir(#{os_type := {unix, _},
|
|
|
|
|
sys_prefix := SysPrefix} = Context) ->
|
|
|
|
|
Dir = filename:join([SysPrefix, "var", "lib", "rabbitmq"]),
|
|
|
|
|
update_context(Context, data_dir, Dir);
|
|
|
|
|
data_dir(#{os_type := {win32, _},
|
|
|
|
|
rabbitmq_base := RabbitmqBase} = Context) ->
|
|
|
|
|
update_context(Context, data_dir, RabbitmqBase).
|
|
|
|
|
|
|
|
|
|
rabbitmq_home(Context) ->
|
|
|
|
|
case get_env_var("RABBITMQ_HOME") of
|
|
|
|
|
false ->
|
|
|
|
|
Dir = filename:dirname(get_default_plugins_path(Context)),
|
|
|
|
|
update_context(Context, rabbitmq_home, Dir, default);
|
|
|
|
|
Value ->
|
|
|
|
|
Dir = normalize_path(Value),
|
|
|
|
|
update_context(Context, rabbitmq_home, Dir, environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%%
|
|
|
|
|
%% RABBITMQ_ALLOW_INPUT
|
|
|
|
|
%% Indicate if an Erlang shell is started or not.
|
|
|
|
|
%% Default: false
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
interactive_shell(Context) ->
|
|
|
|
|
case get_env_var("RABBITMQ_ALLOW_INPUT") of
|
|
|
|
|
false ->
|
|
|
|
|
update_context(Context,
|
|
|
|
|
interactive_shell, false, default);
|
|
|
|
|
Value ->
|
|
|
|
|
update_context(Context,
|
|
|
|
|
interactive_shell, value_is_yes(Value), environment)
|
|
|
|
|
end.
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
%% FIXME: We would need a way to call isatty(3) to make sure the output
|
|
|
|
|
%% is a terminal.
|
|
|
|
|
output_supports_colors(#{os_type := {unix, _}} = Context) ->
|
|
|
|
|
update_context(Context, output_supports_colors, true, default);
|
|
|
|
|
output_supports_colors(#{os_type := {win32, _}} = Context) ->
|
|
|
|
|
update_context(Context, output_supports_colors, false, default).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%% Loading of rabbitmq-env.conf.
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
load_conf_env_file(#{os_type := {unix, _},
|
|
|
|
|
sys_prefix := SysPrefix} = Context) ->
|
|
|
|
|
{ConfEnvFile, Origin} =
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_CONF_ENV_FILE") of
|
|
|
|
|
false ->
|
|
|
|
|
File = filename:join(
|
|
|
|
|
[SysPrefix, "etc", "rabbitmq", "rabbitmq-env.conf"]),
|
|
|
|
|
{File, default};
|
|
|
|
|
Value ->
|
|
|
|
|
{normalize_path(Value), environment}
|
|
|
|
|
end,
|
|
|
|
|
Context1 = update_context(Context, conf_env_file, ConfEnvFile, Origin),
|
2019-09-03 23:28:30 +08:00
|
|
|
case loading_conf_env_file_enabled(Context1) of
|
|
|
|
|
true ->
|
|
|
|
|
case filelib:is_regular(ConfEnvFile) of
|
|
|
|
|
false ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
"No $RABBITMQ_CONF_ENV_FILE (~ts)", [ConfEnvFile]),
|
|
|
|
|
Context1;
|
|
|
|
|
true ->
|
|
|
|
|
case os:find_executable("sh") of
|
|
|
|
|
false -> Context1;
|
|
|
|
|
Sh -> do_load_conf_env_file(Context1,
|
|
|
|
|
Sh,
|
|
|
|
|
ConfEnvFile)
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
false ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
"Loading of $RABBITMQ_CONF_ENV_FILE (~ts) is disabled",
|
|
|
|
|
[ConfEnvFile]),
|
|
|
|
|
Context1
|
|
|
|
|
end;
|
2020-01-21 01:38:59 +08:00
|
|
|
load_conf_env_file(#{os_type := {win32, _},
|
|
|
|
|
rabbitmq_base := RabbitmqBase} = Context) ->
|
|
|
|
|
{ConfEnvFile, Origin} =
|
|
|
|
|
case get_prefixed_env_var("RABBITMQ_CONF_ENV_FILE") of
|
|
|
|
|
false ->
|
|
|
|
|
File = filename:join([RabbitmqBase, "rabbitmq-env-conf.bat"]),
|
|
|
|
|
{File, default};
|
|
|
|
|
Value ->
|
|
|
|
|
{normalize_path(Value), environment}
|
|
|
|
|
end,
|
|
|
|
|
Context1 = update_context(Context, conf_env_file, ConfEnvFile, Origin),
|
2019-09-03 23:28:30 +08:00
|
|
|
case loading_conf_env_file_enabled(Context1) of
|
|
|
|
|
true ->
|
|
|
|
|
rabbit_log_prelaunch:notice(
|
|
|
|
|
"Loading of $RABBITMQ_CONF_ENV_FILE (~s) "
|
|
|
|
|
"is not implemented for Windows",
|
|
|
|
|
[ConfEnvFile]),
|
|
|
|
|
Context1;
|
|
|
|
|
false ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
"Loading of $RABBITMQ_CONF_ENV_FILE (~ts) is disabled",
|
|
|
|
|
[ConfEnvFile]),
|
|
|
|
|
Context1
|
|
|
|
|
end;
|
|
|
|
|
load_conf_env_file(Context) ->
|
|
|
|
|
Context.
|
|
|
|
|
|
2019-12-12 19:18:41 +08:00
|
|
|
-spec loading_conf_env_file_enabled(map()) -> boolean().
|
|
|
|
|
|
2019-09-03 23:28:30 +08:00
|
|
|
-ifdef(TEST).
|
|
|
|
|
loading_conf_env_file_enabled(_) ->
|
|
|
|
|
persistent_term:get({?MODULE, load_conf_env_file}, true).
|
|
|
|
|
-else.
|
|
|
|
|
loading_conf_env_file_enabled(_) ->
|
2019-12-12 20:01:09 +08:00
|
|
|
%% When this module is built without `TEST` defined, we want this
|
2019-12-12 19:18:41 +08:00
|
|
|
%% function to always return true. However, this makes Dialyzer
|
|
|
|
|
%% think it can only return true: this is not the case when the
|
|
|
|
|
%% module is compiled with `TEST` defined. The following line is
|
|
|
|
|
%% here to trick Dialyzer.
|
|
|
|
|
erlang:get({?MODULE, always_undefined}) =:= undefined.
|
2019-09-03 23:28:30 +08:00
|
|
|
-endif.
|
|
|
|
|
|
|
|
|
|
do_load_conf_env_file(Context, Sh, ConfEnvFile) ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
"Sourcing $RABBITMQ_CONF_ENV_FILE: ~ts", [ConfEnvFile]),
|
|
|
|
|
Marker = rabbit_misc:format(
|
|
|
|
|
"-----BEGIN VARS LIST FOR PID ~s-----", [os:getpid()]),
|
|
|
|
|
Script = rabbit_misc:format(
|
|
|
|
|
". \"~ts\" && "
|
|
|
|
|
"echo \"~s\" && "
|
|
|
|
|
"set", [ConfEnvFile, Marker]),
|
|
|
|
|
Args = ["-ex", "-c", Script],
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
#{sys_prefix := SysPrefix,
|
|
|
|
|
rabbitmq_home := RabbitmqHome} = Context,
|
2019-09-03 23:28:30 +08:00
|
|
|
MainConfigFile = re:replace(
|
|
|
|
|
get_default_main_config_file(Context),
|
|
|
|
|
"\\.(conf|config)$", "", [{return, list}]),
|
|
|
|
|
Env = [
|
|
|
|
|
{"SYS_PREFIX", SysPrefix},
|
|
|
|
|
{"RABBITMQ_HOME", RabbitmqHome},
|
|
|
|
|
{"CONFIG_FILE", MainConfigFile},
|
|
|
|
|
{"ADVANCED_CONFIG_FILE", get_default_advanced_config_file(Context)},
|
|
|
|
|
{"MNESIA_BASE", get_default_mnesia_base_dir(Context)},
|
|
|
|
|
{"ENABLED_PLUGINS_FILE", get_default_enabled_plugins_file(Context)},
|
|
|
|
|
{"PLUGINS_DIR", get_default_plugins_path_from_env(Context)},
|
|
|
|
|
{"CONF_ENV_FILE_PHASE", "rabbtimq-prelaunch"}
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
Port = erlang:open_port(
|
|
|
|
|
{spawn_executable, Sh},
|
|
|
|
|
[{args, Args},
|
|
|
|
|
{env, Env},
|
|
|
|
|
binary,
|
|
|
|
|
use_stdio,
|
|
|
|
|
stderr_to_stdout,
|
|
|
|
|
exit_status]),
|
|
|
|
|
collect_sh_output(Context, Port, Marker, <<>>).
|
|
|
|
|
|
|
|
|
|
collect_sh_output(Context, Port, Marker, Output) ->
|
|
|
|
|
receive
|
|
|
|
|
{Port, {exit_status, ExitStatus}} ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
"$RABBITMQ_CONF_ENV_FILE exit status: ~b", [ExitStatus]),
|
|
|
|
|
DecodedOutput = unicode:characters_to_list(Output),
|
|
|
|
|
Lines = string:split(string:trim(DecodedOutput), "\n", all),
|
|
|
|
|
rabbit_log_prelaunch:debug("$RABBITMQ_CONF_ENV_FILE output:"),
|
|
|
|
|
[rabbit_log_prelaunch:debug(" ~ts", [Line])
|
|
|
|
|
|| Line <- Lines],
|
|
|
|
|
case ExitStatus of
|
|
|
|
|
0 -> parse_conf_env_file_output(Context, Marker, Lines);
|
|
|
|
|
_ -> Context
|
|
|
|
|
end;
|
|
|
|
|
{Port, {data, Chunk}} ->
|
|
|
|
|
collect_sh_output(Context, Port, Marker, [Output, Chunk])
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
parse_conf_env_file_output(Context, _, []) ->
|
|
|
|
|
Context;
|
|
|
|
|
parse_conf_env_file_output(Context, Marker, [Marker | Lines]) ->
|
|
|
|
|
%% Found our marker, let's parse variables.
|
|
|
|
|
parse_conf_env_file_output1(Context, Lines, #{});
|
|
|
|
|
parse_conf_env_file_output(Context, Marker, [_ | Lines]) ->
|
|
|
|
|
parse_conf_env_file_output(Context, Marker, Lines).
|
|
|
|
|
|
|
|
|
|
parse_conf_env_file_output1(Context, [], Vars) ->
|
|
|
|
|
%% Re-export variables.
|
|
|
|
|
lists:foreach(
|
|
|
|
|
fun(Var) ->
|
|
|
|
|
IsUsed = var_is_used(Var),
|
|
|
|
|
IsSet = var_is_set(Var),
|
|
|
|
|
case IsUsed andalso not IsSet of
|
|
|
|
|
true ->
|
|
|
|
|
rabbit_log_prelaunch:debug(
|
|
|
|
|
"$RABBITMQ_CONF_ENV_FILE: re-exporting variable $~s",
|
|
|
|
|
[Var]),
|
|
|
|
|
os:putenv(Var, maps:get(Var, Vars));
|
|
|
|
|
false ->
|
|
|
|
|
ok
|
|
|
|
|
end
|
|
|
|
|
end, lists:sort(maps:keys(Vars))),
|
|
|
|
|
Context;
|
|
|
|
|
parse_conf_env_file_output1(Context, [Line | Lines], Vars) ->
|
|
|
|
|
SetXOutput = is_sh_set_x_output(Line),
|
|
|
|
|
ShFunction = is_sh_function(Line, Lines),
|
|
|
|
|
if
|
|
|
|
|
SetXOutput ->
|
|
|
|
|
parse_conf_env_file_output1(Context, Lines, Vars);
|
|
|
|
|
ShFunction ->
|
|
|
|
|
skip_sh_function(Context, Lines, Vars);
|
|
|
|
|
true ->
|
|
|
|
|
case string:split(Line, "=") of
|
|
|
|
|
[Var, IncompleteValue] ->
|
|
|
|
|
{Value, Lines1} = parse_sh_literal(IncompleteValue, Lines),
|
|
|
|
|
Vars1 = Vars#{Var => Value},
|
|
|
|
|
parse_conf_env_file_output1(Context, Lines1, Vars1);
|
|
|
|
|
_ ->
|
|
|
|
|
%% Parsing failed somehow.
|
|
|
|
|
rabbit_log_prelaunch:warning(
|
|
|
|
|
"Failed to parse $RABBITMQ_CONF_ENV_FILE output: ~p",
|
|
|
|
|
[Line]),
|
|
|
|
|
Context
|
|
|
|
|
end
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
is_sh_set_x_output(Line) ->
|
|
|
|
|
re:run(Line, "^\\++ ", [{capture, none}]) =:= match.
|
|
|
|
|
|
|
|
|
|
is_sh_function(_, []) ->
|
|
|
|
|
false;
|
|
|
|
|
is_sh_function(Line, Lines) ->
|
|
|
|
|
re:run(Line, "\\s\\(\\)\\s*$", [{capture, none}]) =:= match
|
|
|
|
|
andalso
|
|
|
|
|
re:run(hd(Lines), "^\\s*\\{\\s*$", [{capture, none}]) =:= match.
|
|
|
|
|
|
|
|
|
|
parse_sh_literal("'" ++ SingleQuoted, Lines) ->
|
|
|
|
|
parse_single_quoted_literal(SingleQuoted, Lines, "");
|
|
|
|
|
parse_sh_literal("$'" ++ DollarSingleQuoted, Lines) ->
|
|
|
|
|
parse_dollar_single_quoted_literal(DollarSingleQuoted, Lines, "");
|
|
|
|
|
parse_sh_literal(Unquoted, Lines) ->
|
|
|
|
|
{Unquoted, Lines}.
|
|
|
|
|
|
|
|
|
|
parse_single_quoted_literal([$'], Lines, Literal) ->
|
|
|
|
|
%% We reached the closing single quote.
|
|
|
|
|
{lists:reverse(Literal), Lines};
|
|
|
|
|
parse_single_quoted_literal([], [Line | Lines], Literal) ->
|
|
|
|
|
%% We reached the end of line before finding the closing single
|
|
|
|
|
%% quote. The literal continues on the next line and includes that
|
|
|
|
|
%% newline character.
|
|
|
|
|
parse_single_quoted_literal(Line, Lines, [$\n | Literal]);
|
|
|
|
|
parse_single_quoted_literal([C | Rest], Lines, Literal) ->
|
|
|
|
|
parse_single_quoted_literal(Rest, Lines, [C | Literal]).
|
|
|
|
|
|
|
|
|
|
parse_dollar_single_quoted_literal([$'], Lines, Literal) ->
|
|
|
|
|
%% We reached the closing single quote.
|
|
|
|
|
{lists:reverse(Literal), Lines};
|
|
|
|
|
parse_dollar_single_quoted_literal([], [Line | Lines], Literal) ->
|
|
|
|
|
%% We reached the end of line before finding the closing single
|
|
|
|
|
%% quote. The literal continues on the next line and includes that
|
|
|
|
|
%% newline character.
|
|
|
|
|
parse_dollar_single_quoted_literal(Line, Lines, [$\n | Literal]);
|
|
|
|
|
parse_dollar_single_quoted_literal([C | Rest], Lines, Literal) ->
|
|
|
|
|
parse_dollar_single_quoted_literal(Rest, Lines, [C | Literal]).
|
|
|
|
|
|
|
|
|
|
skip_sh_function(Context, ["}" | Lines], Vars) ->
|
|
|
|
|
parse_conf_env_file_output1(Context, Lines, Vars);
|
|
|
|
|
skip_sh_function(Context, [_ | Lines], Vars) ->
|
|
|
|
|
skip_sh_function(Context, Lines, Vars).
|
|
|
|
|
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
%% Helpers.
|
|
|
|
|
%% -------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
get_env_var(VarName) ->
|
2020-01-21 01:38:59 +08:00
|
|
|
get_env_var(VarName, []).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
get_env_var(VarName, Options) ->
|
|
|
|
|
KeepEmptyString = lists:member(keep_empty_string_as_is, Options),
|
|
|
|
|
case os:getenv(VarName) of
|
|
|
|
|
false -> false;
|
|
|
|
|
"" when not KeepEmptyString -> false;
|
|
|
|
|
Value -> Value
|
2019-09-03 23:28:30 +08:00
|
|
|
end.
|
|
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
get_prefixed_env_var(VarName) ->
|
|
|
|
|
get_prefixed_env_var(VarName, []).
|
2019-09-03 23:28:30 +08:00
|
|
|
|
2020-01-21 01:38:59 +08:00
|
|
|
get_prefixed_env_var("RABBITMQ_" ++ Suffix = VarName,
|
|
|
|
|
Options) ->
|
|
|
|
|
case get_env_var(VarName, Options) of
|
|
|
|
|
false -> get_env_var(Suffix, Options);
|
2019-09-03 23:28:30 +08:00
|
|
|
Value -> Value
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
var_is_used("RABBITMQ_" ++ _ = PrefixedVar) ->
|
|
|
|
|
lists:member(PrefixedVar, ?USED_ENV_VARS);
|
|
|
|
|
var_is_used(Var) ->
|
|
|
|
|
lists:member("RABBITMQ_" ++ Var, ?USED_ENV_VARS).
|
|
|
|
|
|
|
|
|
|
var_is_set("RABBITMQ_" ++ Var = PrefixedVar) ->
|
|
|
|
|
os:getenv(PrefixedVar) /= false orelse
|
|
|
|
|
os:getenv(Var) /= false;
|
|
|
|
|
var_is_set(Var) ->
|
|
|
|
|
os:getenv("RABBITMQ_" ++ Var) /= false orelse
|
|
|
|
|
os:getenv(Var) /= false.
|
|
|
|
|
|
|
|
|
|
value_is_yes(Value) when is_list(Value) orelse is_binary(Value) ->
|
|
|
|
|
Options = [{capture, none}, caseless],
|
|
|
|
|
re:run(string:trim(Value), "^(1|yes|true)$", Options) =:= match;
|
|
|
|
|
value_is_yes(_) ->
|
|
|
|
|
false.
|
|
|
|
|
|
|
|
|
|
normalize_path("" = Path) ->
|
|
|
|
|
Path;
|
|
|
|
|
normalize_path(Path) ->
|
|
|
|
|
filename:join(filename:split(Path)).
|
|
|
|
|
|
|
|
|
|
this_module_dir() ->
|
2020-01-21 21:50:07 +08:00
|
|
|
File = code:which(?MODULE),
|
2019-09-03 23:28:30 +08:00
|
|
|
%% Possible locations:
|
2020-01-21 21:50:07 +08:00
|
|
|
%% - the rabbit_common plugin (as an .ez archive):
|
2019-09-03 23:28:30 +08:00
|
|
|
%% .../plugins/rabbit_common-$version.ez/rabbit_common-$version/ebin
|
2020-01-21 21:50:07 +08:00
|
|
|
%% - the rabbit_common plugin (as a directory):
|
|
|
|
|
%% .../plugins/rabbit_common-$version/ebin
|
2019-09-03 23:28:30 +08:00
|
|
|
%% - the CLI:
|
|
|
|
|
%% .../escript/$cli
|
|
|
|
|
filename:dirname(File).
|
|
|
|
|
|
|
|
|
|
maybe_setup_dist_for_remote_query(
|
|
|
|
|
#{from_remote_node := offline} = Context) ->
|
|
|
|
|
Context;
|
|
|
|
|
maybe_setup_dist_for_remote_query(
|
|
|
|
|
#{from_remote_node := {RemoteNode, _}} = Context) ->
|
|
|
|
|
{NamePart, HostPart} = rabbit_nodes_common:parts(RemoteNode),
|
2020-01-22 19:05:15 +08:00
|
|
|
NameType = rabbit_nodes_common:name_type(RemoteNode),
|
2019-09-03 23:28:30 +08:00
|
|
|
ok = rabbit_nodes_common:ensure_epmd(),
|
|
|
|
|
Context1 = setup_dist_for_remote_query(
|
|
|
|
|
Context, NamePart, HostPart, NameType, 50),
|
|
|
|
|
case is_rabbitmq_loaded_on_remote_node(Context1) of
|
|
|
|
|
true -> Context1;
|
|
|
|
|
false -> maybe_stop_dist_for_remote_query(
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, from_remote_node, offline))
|
2019-09-03 23:28:30 +08:00
|
|
|
end;
|
|
|
|
|
maybe_setup_dist_for_remote_query(Context) ->
|
|
|
|
|
Context.
|
|
|
|
|
|
|
|
|
|
setup_dist_for_remote_query(
|
|
|
|
|
#{dist_started_for_remote_query := true} = Context,
|
|
|
|
|
_, _, _, _) ->
|
|
|
|
|
Context;
|
|
|
|
|
setup_dist_for_remote_query(Context, _, _, _, 0) ->
|
|
|
|
|
Context;
|
|
|
|
|
setup_dist_for_remote_query(#{from_remote_node := {Remote, _}} = Context,
|
|
|
|
|
NamePart, HostPart, NameType,
|
|
|
|
|
Attempts) ->
|
|
|
|
|
RndNamePart = NamePart ++ "_ctl_" ++ integer_to_list(rand:uniform(100)),
|
|
|
|
|
Nodename = rabbit_nodes_common:make({RndNamePart, HostPart}),
|
|
|
|
|
case net_kernel:start([Nodename, NameType]) of
|
|
|
|
|
{ok, _} ->
|
2020-01-21 01:38:59 +08:00
|
|
|
update_context(Context, dist_started_for_remote_query, true);
|
2019-09-03 23:28:30 +08:00
|
|
|
{error, {already_started, _}} ->
|
|
|
|
|
Context;
|
|
|
|
|
{error, {{already_started, _}, _}} ->
|
|
|
|
|
Context;
|
|
|
|
|
Error ->
|
|
|
|
|
logger:error(
|
|
|
|
|
"rabbit_env: Failed to setup distribution (as ~s) to "
|
|
|
|
|
"query node ~s: ~p",
|
|
|
|
|
[Nodename, Remote, Error]),
|
|
|
|
|
setup_dist_for_remote_query(Context,
|
|
|
|
|
NamePart, HostPart, NameType,
|
|
|
|
|
Attempts - 1)
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
is_rabbitmq_loaded_on_remote_node(
|
|
|
|
|
#{from_remote_node := Remote}) ->
|
|
|
|
|
case query_remote(Remote, application, loaded_applications, []) of
|
|
|
|
|
{ok, Apps} ->
|
|
|
|
|
lists:keymember(mnesia, 1, Apps) andalso
|
|
|
|
|
lists:keymember(rabbit, 1, Apps);
|
|
|
|
|
_ ->
|
|
|
|
|
false
|
|
|
|
|
end.
|
|
|
|
|
|
|
|
|
|
maybe_stop_dist_for_remote_query(
|
|
|
|
|
#{dist_started_for_remote_query := true} = Context) ->
|
|
|
|
|
net_kernel:stop(),
|
|
|
|
|
maps:remove(dist_started_for_remote_query, Context);
|
|
|
|
|
maybe_stop_dist_for_remote_query(Context) ->
|
|
|
|
|
Context.
|
|
|
|
|
|
|
|
|
|
query_remote({RemoteNode, Timeout}, Mod, Func, Args) ->
|
|
|
|
|
Ret = rpc:call(RemoteNode, Mod, Func, Args, Timeout),
|
|
|
|
|
case Ret of
|
|
|
|
|
{badrpc, nodedown} = Error -> Error;
|
|
|
|
|
{badrpc, _} = Error -> throw({query, RemoteNode, Error});
|
|
|
|
|
_ -> {ok, Ret}
|
|
|
|
|
end.
|