diff options
| author | Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com> | 2017-02-20 12:44:34 +0100 |
|---|---|---|
| committer | Jean-Sébastien Pédron <jean-sebastien@rabbitmq.com> | 2017-02-20 17:58:13 +0100 |
| commit | 0151abf37710dfc421523f9235514a438270e032 (patch) | |
| tree | 788e3dc729bcbeaf0d75f85d904dea220aa3ea0f | |
| parent | c4d74f4294169d875bb734164c52d020f10f37c9 (diff) | |
| download | rabbitmq-server-git-0151abf37710dfc421523f9235514a438270e032.tar.gz | |
Restore "Do not expand plugins anymore"
Support for reading static files from Erlang .ez archives was added to
Cowboy and various RabbitMQ plugins were updated to take advantage of
the new API.
So this commit restores the following commits:
7069f3b40daeb5095077bdac19f3837978bc2665
76a8c66c8092cc1c37bb4aa90a0a3d18b27f7d9d
2044cb1eed02e67c4ea749a807694c55ed574756
bc64ac16774aeb403cba87f7e48ad70329dd8b3b
d616cc922dbd73eca7700c50f09e33e6b578b0d9
They were reverted in 72f7c8e70028209ee1c58074c087b4d0cb901e6c because
Cowboy didn't have this support at the time.
Signed-off-by: Gerhard Lazu <gerhard@rabbitmq.com>
[#118562759, #136622317]
| -rwxr-xr-x | scripts/rabbitmq-env | 5 | ||||
| -rw-r--r-- | scripts/rabbitmq-env.bat | 14 | ||||
| -rwxr-xr-x | scripts/rabbitmq-server | 1 | ||||
| -rw-r--r-- | scripts/rabbitmq-server.bat | 1 | ||||
| -rw-r--r-- | scripts/rabbitmq-service.bat | 1 | ||||
| -rw-r--r-- | src/rabbit_plugins.erl | 190 | ||||
| -rw-r--r-- | test/plugins_SUITE.erl | 80 | ||||
| -rw-r--r-- | test/plugins_SUITE_data/plugins1/mock_rabbitmq_plugins_01-0.1.0.ez | bin | 0 -> 3280 bytes |
8 files changed, 212 insertions, 80 deletions
diff --git a/scripts/rabbitmq-env b/scripts/rabbitmq-env index f1624eddf9..e9e83f6313 100755 --- a/scripts/rabbitmq-env +++ b/scripts/rabbitmq-env @@ -220,10 +220,6 @@ rmq_normalize_path_var RABBITMQ_PID_FILE [ "x" = "x$RABBITMQ_BOOT_MODULE" ] && RABBITMQ_BOOT_MODULE=${BOOT_MODULE} -[ "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 @@ -253,7 +249,6 @@ rmq_check_if_shared_with_mnesia \ RABBITMQ_CONFIG_FILE \ RABBITMQ_LOG_BASE \ RABBITMQ_PID_FILE \ - RABBITMQ_PLUGINS_EXPAND_DIR \ RABBITMQ_ENABLED_PLUGINS_FILE \ RABBITMQ_PLUGINS_DIR \ RABBITMQ_LOGS \ diff --git a/scripts/rabbitmq-env.bat b/scripts/rabbitmq-env.bat index 56b2f69b2d..9426019003 100644 --- a/scripts/rabbitmq-env.bat +++ b/scripts/rabbitmq-env.bat @@ -262,20 +262,6 @@ if "!RABBITMQ_BOOT_MODULE!"=="" ( )
)
-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!
- )
-)
-REM FIXME: RabbitMQ removes and recreates RABBITMQ_PLUGINS_EXPAND_DIR
-REM itself. Therefore we can't create it here in advance and escape the
-REM directory name, and RABBITMQ_PLUGINS_EXPAND_DIR must not contain
-REM non-US-ASCII characters.
-
REM [ "x" = "x$RABBITMQ_ENABLED_PLUGINS_FILE" ] && RABBITMQ_ENABLED_PLUGINS_FILE=${ENABLED_PLUGINS_FILE}
if "!RABBITMQ_ENABLED_PLUGINS_FILE!"=="" (
if "!ENABLED_PLUGINS_FILE!"=="" (
diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server index 41d1a81332..655fdc3bcb 100755 --- a/scripts/rabbitmq-server +++ b/scripts/rabbitmq-server @@ -221,7 +221,6 @@ start_rabbitmq_server() { -rabbit lager_handler_upgrade "$RABBITMQ_LAGER_HANDLER_UPGRADE" \ -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 \ diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat index de25f95bdf..a51a327fa5 100644 --- a/scripts/rabbitmq-server.bat +++ b/scripts/rabbitmq-server.bat @@ -180,7 +180,6 @@ if "!ENV_OK!"=="false" ( -rabbit lager_handler !RABBIT_LAGER_HANDLER! ^
-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 ^
diff --git a/scripts/rabbitmq-service.bat b/scripts/rabbitmq-service.bat index 624d18d913..29e7068ab1 100644 --- a/scripts/rabbitmq-service.bat +++ b/scripts/rabbitmq-service.bat @@ -257,7 +257,6 @@ set ERLANG_SERVICE_ARGUMENTS= ^ -rabbit lager_handler !RABBIT_LAGER_HANDLER! ^
-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:\=/!"\" ^
-os_mon start_cpu_sup false ^
-os_mon start_disksup false ^
diff --git a/src/rabbit_plugins.erl b/src/rabbit_plugins.erl index 994e027eac..1b31179c85 100644 --- a/src/rabbit_plugins.erl +++ b/src/rabbit_plugins.erl @@ -67,15 +67,22 @@ ensure(FileJustChanged0) -> {error, {enabled_plugins_mismatch, FileJustChanged, OurFile}} end. -%% @doc Prepares the file system and installs all enabled plugins. setup() -> - {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), - - %% Eliminate the contents of the destination directory - case delete_recursively(ExpandDir) of - ok -> ok; - {error, E1} -> throw({error, {cannot_delete_plugins_expand_dir, - [ExpandDir, E1]}}) + case application:get_env(rabbit, plugins_expand_dir) of + {ok, ExpandDir} -> + case filelib:is_dir(ExpandDir) of + true -> + rabbit_log:info( + "\"~s\" is no longer used to expand plugins.~n" + "RabbitMQ still clears this directory but will " + "stop doing so in the future.", [ExpandDir]), + + _ = delete_recursively(ExpandDir); + false -> + ok + end; + undefined -> + ok end, {ok, EnabledFile} = application:get_env(rabbit, enabled_plugins_file), @@ -128,10 +135,61 @@ extract_schema(#plugin{type = dir, location = Location}, SchemaDir) -> %% @doc Lists the plugins which are currently running. active() -> - {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), - InstalledPlugins = plugin_names(list(ExpandDir)), + LoadedPluginNames = maybe_keep_required_deps(false, loaded_plugin_names()), [App || {App, _, _} <- rabbit_misc:which_applications(), - lists:member(App, InstalledPlugins)]. + lists:member(App, LoadedPluginNames)]. + +loaded_plugin_names() -> + {ok, PluginsPath} = application:get_env(rabbit, plugins_dir), + PluginsDirs = split_path(PluginsPath), + lists:flatmap( + fun(PluginsDir) -> + PluginsDirComponents = filename:split(PluginsDir), + loaded_plugin_names(code:get_path(), PluginsDirComponents, []) + end, + PluginsDirs). + +loaded_plugin_names([Path | OtherPaths], PluginsDirComponents, PluginNames) -> + case lists:sublist(filename:split(Path), length(PluginsDirComponents)) of + PluginsDirComponents -> + case build_plugin_name_from_code_path(Path) of + undefined -> + loaded_plugin_names( + OtherPaths, PluginsDirComponents, PluginNames); + PluginName -> + loaded_plugin_names( + OtherPaths, PluginsDirComponents, + [list_to_atom(PluginName) | PluginNames]) + end; + _ -> + loaded_plugin_names(OtherPaths, PluginsDirComponents, PluginNames) + end; +loaded_plugin_names([], _, PluginNames) -> + PluginNames. + +build_plugin_name_from_code_path(Path) -> + AppPath = case filelib:is_dir(Path) of + true -> + case filelib:wildcard(filename:join(Path, "*.app")) of + [AP | _] -> AP; + [] -> undefined + end; + false -> + EZ = filename:dirname(filename:dirname(Path)), + case filelib:is_regular(EZ) of + true -> + case find_app_path_in_ez(EZ) of + {ok, AP} -> AP; + _ -> undefined + end; + _ -> + undefined + end + end, + case AppPath of + undefined -> undefined; + _ -> filename:basename(AppPath, ".app") + end. %% @doc Get the list of plugins which are ready to be enabled. list(PluginsPath) -> @@ -221,25 +279,19 @@ running_plugins() -> %%---------------------------------------------------------------------------- prepare_plugins(Enabled) -> - {ok, PluginsDistDir} = application:get_env(rabbit, plugins_dir), - {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), - - AllPlugins = list(PluginsDistDir), + AllPlugins = installed_plugins(), Wanted = dependencies(false, Enabled, AllPlugins), WantedPlugins = lookup_plugins(Wanted, AllPlugins), {ValidPlugins, Problems} = validate_plugins(WantedPlugins), maybe_warn_about_invalid_plugins(Problems), - case filelib:ensure_dir(ExpandDir ++ "/") of - ok -> ok; - {error, E2} -> throw({error, {cannot_create_plugins_expand_dir, - [ExpandDir, E2]}}) - end, - [prepare_plugin(Plugin, ExpandDir) || Plugin <- ValidPlugins], - [prepare_dir_plugin(PluginAppDescPath) || - PluginAppDescPath <- filelib:wildcard(ExpandDir ++ "/*/ebin/*.app")], + [prepare_dir_plugin(ValidPlugin) || ValidPlugin <- ValidPlugins], Wanted. +installed_plugins() -> + {ok, PluginsDistDir} = application:get_env(rabbit, plugins_dir), + list(PluginsDistDir). + maybe_warn_about_invalid_plugins([]) -> ok; maybe_warn_about_invalid_plugins(InvalidPlugins) -> @@ -359,40 +411,60 @@ remove_version_preview_part(Version) -> iolist_to_binary(rabbit_semver:format({Ver, {[], []}})). clean_plugins(Plugins) -> - {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), - [clean_plugin(Plugin, ExpandDir) || Plugin <- Plugins]. + [clean_plugin(Plugin) || Plugin <- Plugins]. -clean_plugin(Plugin, ExpandDir) -> +clean_plugin(Plugin) -> {ok, Mods} = application:get_key(Plugin, modules), + PluginEbinDir = code:lib_dir(Plugin, ebin), + application:unload(Plugin), [begin code:soft_purge(Mod), code:delete(Mod), false = code:is_loaded(Mod) end || Mod <- Mods], - delete_recursively(rabbit_misc:format("~s/~s", [ExpandDir, Plugin])). - -prepare_dir_plugin(PluginAppDescPath) -> - PluginEbinDir = filename:dirname(PluginAppDescPath), - Plugin = filename:basename(PluginAppDescPath, ".app"), - code:add_patha(PluginEbinDir), - case filelib:wildcard(PluginEbinDir++ "/*.beam") of - [] -> - ok; - [BeamPath | _] -> - Module = list_to_atom(filename:basename(BeamPath, ".beam")), - case code:ensure_loaded(Module) of - {module, _} -> + + code:del_path(PluginEbinDir). + +plugin_ebin_dir(#plugin{type = ez, location = Location}) -> + case find_app_path_in_ez(Location) of + {ok, AppPath} -> + filename:join(Location, filename:dirname(AppPath)); + {error, Reason} -> + {error, Reason} + end; +plugin_ebin_dir(#plugin{type = dir, location = Location}) -> + filename:join(Location, "ebin"). + +prepare_dir_plugin(#plugin{name = Name} = Plugin) -> + PluginEbinDir = case plugin_ebin_dir(Plugin) of + {error, Reason} -> + throw({plugin_ebin_dir_not_found, Name, Reason}); + Dir -> + Dir + end, + case code:add_patha(PluginEbinDir) of + true -> + case filelib:wildcard(PluginEbinDir++ "/*.beam") of + [] -> ok; - {error, badfile} -> - rabbit_log:error("Failed to enable plugin \"~s\": " - "it may have been built with an " - "incompatible (more recent?) " - "version of Erlang~n", [Plugin]), - throw({plugin_built_with_incompatible_erlang, Plugin}); - Error -> - throw({plugin_module_unloadable, Plugin, Error}) - end + [BeamPath | _] -> + Module = list_to_atom(filename:basename(BeamPath, ".beam")), + case code:ensure_loaded(Module) of + {module, _} -> + ok; + {error, badfile} -> + rabbit_log:error("Failed to enable plugin \"~s\": " + "it may have been built with an " + "incompatible (more recent?) " + "version of Erlang~n", [Name]), + throw({plugin_built_with_incompatible_erlang, Name}); + Error -> + throw({plugin_module_unloadable, Name, Error}) + end + end; + {error, bad_directory} -> + throw({plugin_ebin_path_incorrect, Name, PluginEbinDir}) end. %%---------------------------------------------------------------------------- @@ -403,12 +475,6 @@ delete_recursively(Fn) -> {error, {Path, E}} -> {error, {cannot_delete, Path, E}} end. -prepare_plugin(#plugin{type = ez, location = Location}, ExpandDir) -> - zip:unzip(Location, [{cwd, ExpandDir}]); -prepare_plugin(#plugin{type = dir, name = Name, location = Location}, - ExpandDir) -> - rabbit_file:recursive_copy(Location, filename:join([ExpandDir, Name])). - plugin_info({ez, EZ}) -> case read_app_file(EZ) of {application, Name, Props} -> mkplugin(Name, Props, ez, EZ); @@ -435,14 +501,12 @@ mkplugin(Name, Props, Type, Location) -> broker_version_requirements = BrokerVersions, dependency_version_requirements = DepsVersions}. -read_app_file(EZ) -> +find_app_path_in_ez(EZ) -> case zip:list_dir(EZ) of {ok, [_|ZippedFiles]} -> case find_app_files(ZippedFiles) of [AppPath|_] -> - {ok, [{AppPath, AppFile}]} = - zip:extract(EZ, [{file_list, [AppPath]}, memory]), - parse_binary(AppFile); + {ok, AppPath}; [] -> {error, no_app_file} end; @@ -450,6 +514,16 @@ read_app_file(EZ) -> {error, {invalid_ez, Reason}} end. +read_app_file(EZ) -> + case find_app_path_in_ez(EZ) of + {ok, AppPath} -> + {ok, [{AppPath, AppFile}]} = + zip:extract(EZ, [{file_list, [AppPath]}, memory]), + parse_binary(AppFile); + {error, Reason} -> + {error, Reason} + end. + find_app_files(ZippedFiles) -> {ok, RE} = re:compile("^.*/ebin/.*.app$"), [Path || {zip_file, Path, _, _, _, _} <- ZippedFiles, diff --git a/test/plugins_SUITE.erl b/test/plugins_SUITE.erl new file mode 100644 index 0000000000..8896298df1 --- /dev/null +++ b/test/plugins_SUITE.erl @@ -0,0 +1,80 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(plugins_SUITE). + +-include_lib("common_test/include/ct.hrl"). + +-compile(export_all). + +all() -> + [ + active_with_single_plugin_dir, + active_with_multiple_plugin_dirs + ]. + +%% ------------------------------------------------------------------- +%% Testsuite setup/teardown. +%% ------------------------------------------------------------------- + +init_per_suite(Config) -> + rabbit_ct_helpers:log_environment(), + application:load(rabbit), + rabbit_ct_helpers:run_setup_steps(Config). + +end_per_suite(Config) -> + rabbit_ct_helpers:run_teardown_steps(Config). + +init_per_group(_, Config) -> + Config. + +end_per_group(_, Config) -> + Config. + +init_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_started(Config, Testcase). + +end_per_testcase(Testcase, Config) -> + rabbit_ct_helpers:testcase_finished(Config, Testcase). + +%% ------------------------------------------------------------------- +%% Testcases. +%% ------------------------------------------------------------------- + +active_with_single_plugin_dir(Config) -> + DataDir = rabbit_ct_helpers:get_config(Config, data_dir), + PluginsDir1 = filename:join(DataDir, "plugins1"), + + true = code:add_path(filename:join([PluginsDir1, + "mock_rabbitmq_plugins_01-0.1.0.ez", + "mock_rabbitmq_plugins_01-0.1.0", "ebin"])), + {ok, _} = application:ensure_all_started(mock_rabbitmq_plugins_01), + application:set_env(rabbit, plugins_dir, PluginsDir1), + + [mock_rabbitmq_plugins_01] = rabbit_plugins:active(). + +active_with_multiple_plugin_dirs(Config) -> + DataDir = rabbit_ct_helpers:get_config(Config, data_dir), + PluginsDir1 = filename:join(DataDir, "plugins1"), + PluginsDir2 = filename:join(DataDir, "plugins2"), + + true = code:add_path(filename:join([PluginsDir1, + "mock_rabbitmq_plugins_01-0.1.0.ez", + "mock_rabbitmq_plugins_01-0.1.0", "ebin"])), + {ok, _} = application:ensure_all_started(mock_rabbitmq_plugins_01), + application:set_env(rabbit, plugins_dir, PluginsDir1 ++ ":" ++ PluginsDir2), + + [mock_rabbitmq_plugins_01] = rabbit_plugins:active(). diff --git a/test/plugins_SUITE_data/plugins1/mock_rabbitmq_plugins_01-0.1.0.ez b/test/plugins_SUITE_data/plugins1/mock_rabbitmq_plugins_01-0.1.0.ez Binary files differnew file mode 100644 index 0000000000..40cba9f16b --- /dev/null +++ b/test/plugins_SUITE_data/plugins1/mock_rabbitmq_plugins_01-0.1.0.ez |
