summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJean-Sébastien Pédron <jean-sebastien@rabbitmq.com>2017-02-20 12:44:34 +0100
committerJean-Sébastien Pédron <jean-sebastien@rabbitmq.com>2017-02-20 17:58:13 +0100
commit0151abf37710dfc421523f9235514a438270e032 (patch)
tree788e3dc729bcbeaf0d75f85d904dea220aa3ea0f /src
parentc4d74f4294169d875bb734164c52d020f10f37c9 (diff)
downloadrabbitmq-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.erl190
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,