diff options
| -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 | 3280 -> 0 bytes |
8 files changed, 80 insertions, 212 deletions
diff --git a/scripts/rabbitmq-env b/scripts/rabbitmq-env index e9e83f6313..f1624eddf9 100755 --- a/scripts/rabbitmq-env +++ b/scripts/rabbitmq-env @@ -220,6 +220,10 @@ 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 @@ -249,6 +253,7 @@ 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 9426019003..56b2f69b2d 100644 --- a/scripts/rabbitmq-env.bat +++ b/scripts/rabbitmq-env.bat @@ -262,6 +262,20 @@ 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 655fdc3bcb..41d1a81332 100755 --- a/scripts/rabbitmq-server +++ b/scripts/rabbitmq-server @@ -221,6 +221,7 @@ 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 a51a327fa5..de25f95bdf 100644 --- a/scripts/rabbitmq-server.bat +++ b/scripts/rabbitmq-server.bat @@ -180,6 +180,7 @@ 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 29e7068ab1..624d18d913 100644 --- a/scripts/rabbitmq-service.bat +++ b/scripts/rabbitmq-service.bat @@ -257,6 +257,7 @@ 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 1b31179c85..994e027eac 100644 --- a/src/rabbit_plugins.erl +++ b/src/rabbit_plugins.erl @@ -67,22 +67,15 @@ ensure(FileJustChanged0) -> {error, {enabled_plugins_mismatch, FileJustChanged, OurFile}} end. +%% @doc Prepares the file system and installs all enabled plugins. setup() -> - 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 + {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]}}) end, {ok, EnabledFile} = application:get_env(rabbit, enabled_plugins_file), @@ -135,61 +128,10 @@ extract_schema(#plugin{type = dir, location = Location}, SchemaDir) -> %% @doc Lists the plugins which are currently running. active() -> - LoadedPluginNames = maybe_keep_required_deps(false, loaded_plugin_names()), + {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), + InstalledPlugins = plugin_names(list(ExpandDir)), [App || {App, _, _} <- rabbit_misc:which_applications(), - 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. + lists:member(App, InstalledPlugins)]. %% @doc Get the list of plugins which are ready to be enabled. list(PluginsPath) -> @@ -279,19 +221,25 @@ running_plugins() -> %%---------------------------------------------------------------------------- prepare_plugins(Enabled) -> - AllPlugins = installed_plugins(), + {ok, PluginsDistDir} = application:get_env(rabbit, plugins_dir), + {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), + + AllPlugins = list(PluginsDistDir), 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(ValidPlugin) || ValidPlugin <- ValidPlugins], + [prepare_dir_plugin(PluginAppDescPath) || + PluginAppDescPath <- filelib:wildcard(ExpandDir ++ "/*/ebin/*.app")], 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) -> @@ -411,60 +359,40 @@ remove_version_preview_part(Version) -> iolist_to_binary(rabbit_semver:format({Ver, {[], []}})). clean_plugins(Plugins) -> - [clean_plugin(Plugin) || Plugin <- Plugins]. + {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), + [clean_plugin(Plugin, ExpandDir) || Plugin <- Plugins]. -clean_plugin(Plugin) -> +clean_plugin(Plugin, ExpandDir) -> {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], - - 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 - [] -> + 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, _} -> ok; - [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}) + {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 end. %%---------------------------------------------------------------------------- @@ -475,6 +403,12 @@ 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); @@ -501,12 +435,14 @@ mkplugin(Name, Props, Type, Location) -> broker_version_requirements = BrokerVersions, dependency_version_requirements = DepsVersions}. -find_app_path_in_ez(EZ) -> +read_app_file(EZ) -> case zip:list_dir(EZ) of {ok, [_|ZippedFiles]} -> case find_app_files(ZippedFiles) of [AppPath|_] -> - {ok, AppPath}; + {ok, [{AppPath, AppFile}]} = + zip:extract(EZ, [{file_list, [AppPath]}, memory]), + parse_binary(AppFile); [] -> {error, no_app_file} end; @@ -514,16 +450,6 @@ find_app_path_in_ez(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 deleted file mode 100644 index 8896298df1..0000000000 --- a/test/plugins_SUITE.erl +++ /dev/null @@ -1,80 +0,0 @@ -%% The contents of this file are subject to the Mozilla Public License -%% Version 1.1 (the "License"); you may not use this file except in -%% compliance with the License. You may obtain a copy of the License at -%% 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 differdeleted file mode 100644 index 40cba9f16b..0000000000 --- a/test/plugins_SUITE_data/plugins1/mock_rabbitmq_plugins_01-0.1.0.ez +++ /dev/null |
