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 /src | |
| 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]
Diffstat (limited to 'src')
| -rw-r--r-- | src/rabbit_plugins.erl | 190 |
1 files changed, 132 insertions, 58 deletions
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, |
