Skip to content

Do not expand plugins #1064

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions scripts/rabbitmq-env
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -251,7 +247,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
Expand Down
14 changes: 0 additions & 14 deletions scripts/rabbitmq-env.bat
Original file line number Diff line number Diff line change
Expand Up @@ -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!"=="" (
Expand Down
1 change: 0 additions & 1 deletion scripts/rabbitmq-server
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ start_rabbitmq_server() {
-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 \
Expand Down
1 change: 0 additions & 1 deletion scripts/rabbitmq-server.bat
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,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 ^
Expand Down
1 change: 0 additions & 1 deletion scripts/rabbitmq-service.bat
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,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 ^
Expand Down
190 changes: 131 additions & 59 deletions src/rabbit_plugins.erl
Original file line number Diff line number Diff line change
Expand Up @@ -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 manages 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),
Expand Down Expand Up @@ -128,10 +135,56 @@ 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, PluginsDir} = application:get_env(rabbit, plugins_dir),
PluginsDirComponents = filename:split(PluginsDir),
loaded_plugin_names(code:get_path(), PluginsDirComponents, []).

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) ->
Expand Down Expand Up @@ -221,25 +274,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) ->
Expand Down Expand Up @@ -352,40 +399,60 @@ is_version_supported(Version, ExpectedVersions) ->
end.

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.

%%----------------------------------------------------------------------------
Expand All @@ -396,12 +463,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);
Expand All @@ -428,21 +489,29 @@ 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;
{error, Reason} ->
{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,
Expand Down Expand Up @@ -544,7 +613,10 @@ maybe_keep_required_deps(false, Plugins) ->
%% instance.
application:load(rabbit),
{ok, RabbitDeps} = application:get_key(rabbit, applications),
lists:filter(fun(#plugin{name = Name}) ->
lists:filter(fun
(#plugin{name = Name}) ->
not lists:member(Name, RabbitDeps);
(Name) when is_atom(Name) ->
not lists:member(Name, RabbitDeps)
end,
Plugins).
Expand Down