Merge branch 'master' into rabbitmq-cli-424
This commit is contained in:
		
						commit
						0e577ee358
					
				|  | @ -299,8 +299,8 @@ context_to_app_env_vars1( | |||
|     end, | ||||
|     ok. | ||||
| 
 | ||||
| context_to_code_path(#{plugins_path := PluginsPath}) -> | ||||
|     Dirs = get_user_lib_dirs(PluginsPath), | ||||
| context_to_code_path(#{os_type := OSType, plugins_path := PluginsPath}) -> | ||||
|     Dirs = get_user_lib_dirs(OSType, PluginsPath), | ||||
|     code:add_pathsa(lists:reverse(Dirs)). | ||||
| 
 | ||||
| %% ------------------------------------------------------------------- | ||||
|  | @ -309,8 +309,8 @@ context_to_code_path(#{plugins_path := PluginsPath}) -> | |||
| %% The goal is to mimic the behavior of the `$ERL_LIBS` environment | ||||
| %% variable. | ||||
| 
 | ||||
| get_user_lib_dirs(Path) -> | ||||
|     Sep = case os:type() of | ||||
| get_user_lib_dirs(OSType, Path) -> | ||||
|     Sep = case OSType of | ||||
|               {win32, _} -> ";"; | ||||
|               _          -> ":" | ||||
|           end, | ||||
|  | @ -1426,11 +1426,28 @@ load_conf_env_file(#{os_type := {win32, _}, | |||
|     Context1 = update_context(Context, conf_env_file, ConfEnvFile, Origin), | ||||
|     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]), | ||||
|             case filelib:is_regular(ConfEnvFile) of | ||||
|                 false -> | ||||
|                     rabbit_log_prelaunch:debug( | ||||
|                       "No $RABBITMQ_CONF_ENV_FILE (~ts)", [ConfEnvFile]), | ||||
|                     Context1; | ||||
|                 true -> | ||||
|                     case os:find_executable("cmd.exe") of | ||||
|                         false -> | ||||
|                             Cmd = os:getenv("ComSpec"), | ||||
|                             CmdExists = | ||||
|                               Cmd =/= false andalso | ||||
|                               filelib:is_regular(Cmd), | ||||
|                             case CmdExists of | ||||
|                                 false -> Context1; | ||||
|                                 true  -> do_load_conf_env_file(Context1, | ||||
|                                                                Cmd, | ||||
|                                                                ConfEnvFile) | ||||
|                             end; | ||||
|                         Cmd -> | ||||
|                             do_load_conf_env_file(Context1, Cmd, ConfEnvFile) | ||||
|                     end | ||||
|             end; | ||||
|         false -> | ||||
|             rabbit_log_prelaunch:debug( | ||||
|               "Loading of $RABBITMQ_CONF_ENV_FILE (~ts) is disabled", | ||||
|  | @ -1455,22 +1472,28 @@ loading_conf_env_file_enabled(_) -> | |||
|     erlang:get({?MODULE, always_undefined}) =:= undefined. | ||||
| -endif. | ||||
| 
 | ||||
| do_load_conf_env_file(Context, Sh, ConfEnvFile) -> | ||||
| do_load_conf_env_file(#{os_type := {unix, _}} = 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()]), | ||||
| 
 | ||||
|     %% The script below sources the `CONF_ENV_FILE` file, then it shows a | ||||
|     %% marker line and all environment variables. | ||||
|     %% | ||||
|     %% The marker line is useful to distinguish any output from the sourced | ||||
|     %% script from the variables we are interested in. | ||||
|     Marker = vars_list_marker(), | ||||
|     Script = rabbit_misc:format( | ||||
|                ". \"~ts\" && " | ||||
|                "echo \"~s\" && " | ||||
|                "set", [ConfEnvFile, Marker]), | ||||
|     Args = ["-ex", "-c", Script], | ||||
| 
 | ||||
|     #{sys_prefix := SysPrefix, | ||||
|       rabbitmq_home := RabbitmqHome} = Context, | ||||
|     MainConfigFile = re:replace( | ||||
|                        get_default_main_config_file(Context), | ||||
|                        "\\.(conf|config)$", "", [{return, list}]), | ||||
| 
 | ||||
|     %% The variables below are those the `CONF_ENV_FILE` file can expect. | ||||
|     Env = [ | ||||
|            {"SYS_PREFIX", SysPrefix}, | ||||
|            {"RABBITMQ_HOME", RabbitmqHome}, | ||||
|  | @ -1482,34 +1505,92 @@ do_load_conf_env_file(Context, Sh, ConfEnvFile) -> | |||
|            {"CONF_ENV_FILE_PHASE", "rabbtimq-prelaunch"} | ||||
|           ], | ||||
| 
 | ||||
|     Port = erlang:open_port( | ||||
|              {spawn_executable, Sh}, | ||||
|              [{args, Args}, | ||||
|     Args = ["-ex", "-c", Script], | ||||
|     Opts = [{args, Args}, | ||||
|             {env, Env}, | ||||
|             binary, | ||||
|             use_stdio, | ||||
|             stderr_to_stdout, | ||||
|               exit_status]), | ||||
|     collect_sh_output(Context, Port, Marker, <<>>). | ||||
|             exit_status], | ||||
|     Port = erlang:open_port({spawn_executable, Sh}, Opts), | ||||
|     collect_conf_env_file_output(Context, Port, Marker, <<>>); | ||||
| do_load_conf_env_file(#{os_type := {win32, _}} = Context, Cmd, ConfEnvFile) -> | ||||
|     %% rabbitmq/rabbitmq-common#392 | ||||
|     rabbit_log_prelaunch:debug( | ||||
|       "Executing $RABBITMQ_CONF_ENV_FILE: ~ts", [ConfEnvFile]), | ||||
| 
 | ||||
| collect_sh_output(Context, Port, Marker, Output) -> | ||||
|     %% The script below executes the `CONF_ENV_FILE` file, then it shows a | ||||
|     %% marker line and all environment variables. | ||||
|     %% | ||||
|     %% The marker line is useful to distinguish any output from the sourced | ||||
|     %% script from the variables we are interested in. | ||||
|     %% | ||||
|     %% Arguments are split into a list of strings to support a filename with | ||||
|     %% whitespaces in the path. | ||||
|     Marker = vars_list_marker(), | ||||
|     Script = [ConfEnvFile, "&&", | ||||
|               "echo", Marker, "&&", | ||||
|               "set"], | ||||
| 
 | ||||
|     #{rabbitmq_base := RabbitmqBase, | ||||
|       rabbitmq_home := RabbitmqHome} = Context, | ||||
|     MainConfigFile = re:replace( | ||||
|                        get_default_main_config_file(Context), | ||||
|                        "\\.(conf|config)$", "", [{return, list}]), | ||||
| 
 | ||||
|     %% The variables below are those the `CONF_ENV_FILE` file can expect. | ||||
|     Env = [ | ||||
|            {"RABBITMQ_BASE", RabbitmqBase}, | ||||
|            {"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"} | ||||
|           ], | ||||
| 
 | ||||
|     Args = ["/Q", "/C" | Script], | ||||
|     Opts = [{args, Args}, | ||||
|             {env, Env}, | ||||
|             hide, | ||||
|             binary, | ||||
|             stderr_to_stdout, | ||||
|             exit_status], | ||||
|     Port = erlang:open_port({spawn_executable, Cmd}, Opts), | ||||
|     collect_conf_env_file_output(Context, Port, "\"" ++ Marker ++ "\" ", <<>>). | ||||
| 
 | ||||
| vars_list_marker() -> | ||||
|     rabbit_misc:format( | ||||
|       "-----BEGIN VARS LIST FOR PID ~s-----", [os:getpid()]). | ||||
| 
 | ||||
| collect_conf_env_file_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], | ||||
|             Lines = post_port_cmd_output(Context, Output, ExitStatus), | ||||
|             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]) | ||||
|             collect_conf_env_file_output( | ||||
|               Context, Port, Marker, [Output, Chunk]) | ||||
|     end. | ||||
| 
 | ||||
| post_port_cmd_output(#{os_type := {OSType, _}}, Output, ExitStatus) -> | ||||
|     rabbit_log_prelaunch:debug( | ||||
|       "$RABBITMQ_CONF_ENV_FILE exit status: ~b", | ||||
|       [ExitStatus]), | ||||
|     DecodedOutput = unicode:characters_to_list(Output), | ||||
|     LineSep = case OSType of | ||||
|                   win32 -> "\r\n"; | ||||
|                   _     -> "\n" | ||||
|               end, | ||||
|     Lines = string:split(string:trim(DecodedOutput), LineSep, all), | ||||
|     rabbit_log_prelaunch:debug("$RABBITMQ_CONF_ENV_FILE output:"), | ||||
|     [rabbit_log_prelaunch:debug("  ~ts", [Line]) || Line <- Lines], | ||||
|     Lines. | ||||
| 
 | ||||
| parse_conf_env_file_output(Context, _, []) -> | ||||
|     Context; | ||||
| parse_conf_env_file_output(Context, Marker, [Marker | Lines]) -> | ||||
|  |  | |||
|  | @ -22,6 +22,8 @@ | |||
| -export([all/0, | ||||
|          suite/0, | ||||
|          groups/0, | ||||
|          init_per_suite/1, | ||||
|          end_per_suite/1, | ||||
|          init_per_group/2, | ||||
|          end_per_group/2, | ||||
|          init_per_testcase/2, | ||||
|  | @ -110,6 +112,14 @@ groups() -> | |||
|      {parallel_tests, [parallel], all()} | ||||
|     ]. | ||||
| 
 | ||||
| init_per_suite(Config) -> | ||||
|     persistent_term:put({rabbit_env, load_conf_env_file}, false), | ||||
|     Config. | ||||
| 
 | ||||
| end_per_suite(Config) -> | ||||
|     persistent_term:erase({rabbit_env, load_conf_env_file}), | ||||
|     Config. | ||||
| 
 | ||||
| init_per_group(_, Config) -> Config. | ||||
| end_per_group(_, Config) -> Config. | ||||
| 
 | ||||
|  | @ -138,7 +148,6 @@ check_data_dir(_) -> | |||
| check_default_values(_) -> | ||||
|     %% When `rabbit_env` is built with `TEST` defined, we can override | ||||
|     %% the OS type. | ||||
|     persistent_term:put({rabbit_env, load_conf_env_file}, false), | ||||
|     persistent_term:put({rabbit_env, os_type}, {unix, undefined}), | ||||
|     UnixContext = rabbit_env:get_context(), | ||||
| 
 | ||||
|  | @ -152,7 +161,6 @@ check_default_values(_) -> | |||
|     end, | ||||
| 
 | ||||
|     persistent_term:erase({rabbit_env, os_type}), | ||||
|     persistent_term:erase({rabbit_env, load_conf_env_file}), | ||||
| 
 | ||||
|     {RFFValue, RFFOrigin} = forced_feature_flags_on_init_expect(), | ||||
| 
 | ||||
|  | @ -359,12 +367,10 @@ check_values_from_reachable_remote_node(Config) -> | |||
|     wait_for_remote_node(Node), | ||||
| 
 | ||||
|     try | ||||
|         persistent_term:put({rabbit_env, load_conf_env_file}, false), | ||||
|         persistent_term:put({rabbit_env, os_type}, {unix, undefined}), | ||||
|         UnixContext = rabbit_env:get_context(Node), | ||||
| 
 | ||||
|         persistent_term:erase({rabbit_env, os_type}), | ||||
|         persistent_term:erase({rabbit_env, load_conf_env_file}), | ||||
| 
 | ||||
|         {RFFValue, RFFOrigin} = forced_feature_flags_on_init_expect(), | ||||
| 
 | ||||
|  | @ -475,12 +481,10 @@ check_values_from_offline_remote_node(_) -> | |||
|     NodeS = atom_to_list(Node), | ||||
|     true = os:putenv("RABBITMQ_NODENAME", NodeS), | ||||
| 
 | ||||
|     persistent_term:put({rabbit_env, load_conf_env_file}, false), | ||||
|     persistent_term:put({rabbit_env, os_type}, {unix, undefined}), | ||||
|     UnixContext = rabbit_env:get_context(offline), | ||||
| 
 | ||||
|     persistent_term:erase({rabbit_env, os_type}), | ||||
|     persistent_term:erase({rabbit_env, load_conf_env_file}), | ||||
|     os:unsetenv("RABBITMQ_NODENAME"), | ||||
| 
 | ||||
|     {RFFValue, RFFOrigin} = forced_feature_flags_on_init_expect(), | ||||
|  | @ -568,12 +572,10 @@ check_values_from_offline_remote_node(_) -> | |||
| check_context_to_app_env_vars(_) -> | ||||
|     %% When `rabbit_env` is built with `TEST` defined, we can override | ||||
|     %% the OS type. | ||||
|     persistent_term:put({rabbit_env, load_conf_env_file}, false), | ||||
|     persistent_term:put({rabbit_env, os_type}, {unix, undefined}), | ||||
|     UnixContext = rabbit_env:get_context(), | ||||
| 
 | ||||
|     persistent_term:erase({rabbit_env, os_type}), | ||||
|     persistent_term:erase({rabbit_env, load_conf_env_file}), | ||||
| 
 | ||||
|     Vars = [{mnesia, dir, maps:get(mnesia_dir, UnixContext)}, | ||||
|             {ra, data_dir, maps:get(quorum_queue_dir, UnixContext)}, | ||||
|  | @ -630,36 +632,76 @@ check_context_to_code_path(Config) -> | |||
|     ok = file:make_dir(MyPlugin2Dir), | ||||
|     ok = file:make_dir(MyPlugin2EbinDir), | ||||
| 
 | ||||
|     %% When `rabbit_env` is built with `TEST` defined, we can override | ||||
|     %% the OS type. | ||||
|     PluginsPath = PluginsDir1 ++ ":" ++ PluginsDir2, | ||||
|     true = os:putenv("RABBITMQ_PLUGINS_DIR", PluginsPath), | ||||
|     persistent_term:put({rabbit_env, load_conf_env_file}, false), | ||||
|     %% On Unix. | ||||
|     %% | ||||
|     %% We can't test the Unix codepath on Windows because the drive letter | ||||
|     %% separator conflicts with the path separator (they are both ':'). | ||||
|     %% However, the Windows codepath can be tested on both Unix and Windows. | ||||
|     case os:type() of | ||||
|         {unix, _} -> | ||||
|             UnixPluginsPath = PluginsDir1 ++ ":" ++ PluginsDir2, | ||||
|             true = os:putenv("RABBITMQ_PLUGINS_DIR", UnixPluginsPath), | ||||
|             persistent_term:put({rabbit_env, os_type}, {unix, undefined}), | ||||
|             UnixContext = rabbit_env:get_context(), | ||||
| 
 | ||||
|             persistent_term:erase({rabbit_env, os_type}), | ||||
|     persistent_term:erase({rabbit_env, load_conf_env_file}), | ||||
|             os:unsetenv("RABBITMQ_PLUGINS_DIR"), | ||||
| 
 | ||||
|     ?assertEqual(PluginsPath, maps:get(plugins_path, UnixContext)), | ||||
|             ?assertEqual(UnixPluginsPath, maps:get(plugins_path, UnixContext)), | ||||
| 
 | ||||
|     OldCodePath = code:get_path(), | ||||
|     ?assertNot(lists:member(MyPlugin1EbinDir, OldCodePath)), | ||||
|     ?assertNot(lists:member(MyPlugin2EbinDir, OldCodePath)), | ||||
|             OldCodePath1 = code:get_path(), | ||||
|             ?assertNot(lists:member(MyPlugin1EbinDir, OldCodePath1)), | ||||
|             ?assertNot(lists:member(MyPlugin2EbinDir, OldCodePath1)), | ||||
| 
 | ||||
|             rabbit_env:context_to_code_path(UnixContext), | ||||
| 
 | ||||
|     NewCodePath = code:get_path(), | ||||
|     ?assert(lists:member(MyPlugin1EbinDir, NewCodePath)), | ||||
|     ?assert(lists:member(MyPlugin2EbinDir, NewCodePath)), | ||||
|             NewCodePath1 = code:get_path(), | ||||
|             ?assert(lists:member(MyPlugin1EbinDir, NewCodePath1)), | ||||
|             ?assert(lists:member(MyPlugin2EbinDir, NewCodePath1)), | ||||
|             ?assertEqual( | ||||
|                [MyPlugin1EbinDir, MyPlugin2EbinDir], | ||||
|                lists:filter( | ||||
|                  fun(Dir) -> | ||||
|                          Dir =:= MyPlugin1EbinDir orelse | ||||
|                          Dir =:= MyPlugin2EbinDir | ||||
|          end, NewCodePath)). | ||||
|                  end, NewCodePath1)), | ||||
| 
 | ||||
|             true = code:del_path(MyPlugin1EbinDir), | ||||
|             true = code:del_path(MyPlugin2EbinDir); | ||||
|         _ -> | ||||
|             ok | ||||
|     end, | ||||
| 
 | ||||
|     %% On Windows. | ||||
|     Win32PluginsPath = PluginsDir1 ++ ";" ++ PluginsDir2, | ||||
|     true = os:putenv("RABBITMQ_PLUGINS_DIR", Win32PluginsPath), | ||||
|     persistent_term:put({rabbit_env, os_type}, {win32, undefined}), | ||||
|     Win32Context = rabbit_env:get_context(), | ||||
| 
 | ||||
|     persistent_term:erase({rabbit_env, os_type}), | ||||
|     os:unsetenv("RABBITMQ_PLUGINS_DIR"), | ||||
| 
 | ||||
|     ?assertEqual(Win32PluginsPath, maps:get(plugins_path, Win32Context)), | ||||
| 
 | ||||
|     OldCodePath2 = code:get_path(), | ||||
|     ?assertNot(lists:member(MyPlugin1EbinDir, OldCodePath2)), | ||||
|     ?assertNot(lists:member(MyPlugin2EbinDir, OldCodePath2)), | ||||
| 
 | ||||
|     rabbit_env:context_to_code_path(Win32Context), | ||||
| 
 | ||||
|     NewCodePath2 = code:get_path(), | ||||
|     ?assert(lists:member(MyPlugin1EbinDir, NewCodePath2)), | ||||
|     ?assert(lists:member(MyPlugin2EbinDir, NewCodePath2)), | ||||
|     ?assertEqual( | ||||
|        [MyPlugin1EbinDir, MyPlugin2EbinDir], | ||||
|        lists:filter( | ||||
|          fun(Dir) -> | ||||
|                  Dir =:= MyPlugin1EbinDir orelse | ||||
|                  Dir =:= MyPlugin2EbinDir | ||||
|          end, NewCodePath2)), | ||||
| 
 | ||||
|     true = code:del_path(MyPlugin1EbinDir), | ||||
|     true = code:del_path(MyPlugin2EbinDir). | ||||
| 
 | ||||
| check_RABBITMQ_ADVANCED_CONFIG_FILE(_) -> | ||||
|     Value1 = random_string(), | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue