2016-06-20 23:52:36 +08:00
|
|
|
## 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.
|
2017-01-10 22:42:40 +08:00
|
|
|
## Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved.
|
2016-11-15 01:52:08 +08:00
|
|
|
alias RabbitMQ.CLI.Core.Helpers, as: CliHelpers
|
|
|
|
alias RabbitMQ.CLI.Core.Config, as: Config
|
2017-11-28 02:49:08 +08:00
|
|
|
alias RabbitMQ.CLI.Core.Validators, as: Validators
|
2016-06-20 23:52:36 +08:00
|
|
|
|
|
|
|
defmodule RabbitMQ.CLI.Plugins.Helpers do
|
2016-11-15 01:52:08 +08:00
|
|
|
import Rabbitmq.Atom.Coerce
|
2016-06-22 22:32:49 +08:00
|
|
|
import RabbitCommon.Records
|
|
|
|
|
2017-11-28 02:49:08 +08:00
|
|
|
def mode(opts) do
|
|
|
|
%{online: online, offline: offline} = opts
|
|
|
|
case {online, offline} do
|
|
|
|
{true, false} -> :online;
|
|
|
|
{false, true} -> :offline;
|
|
|
|
{false, false} -> :best_effort
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def can_set_plugins_with_mode(args, opts) do
|
|
|
|
mode = mode(opts)
|
|
|
|
case mode(opts) do
|
|
|
|
## Can always set offline plugins list
|
|
|
|
:offline -> :ok;
|
|
|
|
## It should fall back to offline mode in case of errors
|
|
|
|
:best_effort -> :ok;
|
|
|
|
## The running node is required
|
|
|
|
:online ->
|
|
|
|
Validators.chain([&Validators.node_is_running/2,
|
|
|
|
&Validators.rabbit_is_running/2],
|
|
|
|
[args, opts])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-06-20 23:52:36 +08:00
|
|
|
def list(opts) do
|
2016-10-25 20:23:00 +08:00
|
|
|
{:ok, dir} = CliHelpers.plugins_dir(opts)
|
2016-06-20 23:52:36 +08:00
|
|
|
add_all_to_path(dir)
|
2017-06-26 18:59:46 +08:00
|
|
|
:lists.usort(:rabbit_plugins.list(to_charlist(dir)))
|
2016-06-20 23:52:36 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def read_enabled(opts) do
|
2016-11-08 22:45:59 +08:00
|
|
|
case enabled_plugins_file(opts) do
|
|
|
|
{:ok, enabled} ->
|
2017-06-26 18:59:46 +08:00
|
|
|
:rabbit_plugins.read_enabled(to_charlist(enabled));
|
2016-11-08 22:45:59 +08:00
|
|
|
# Existence of enabled_plugins_file should be validated separately
|
|
|
|
{:error, :no_plugins_file} ->
|
|
|
|
[]
|
|
|
|
end
|
2016-06-20 23:52:36 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def enabled_plugins_file(opts) do
|
2016-10-25 20:23:00 +08:00
|
|
|
case Config.get_option(:enabled_plugins_file, opts) do
|
2016-06-20 23:52:36 +08:00
|
|
|
nil -> {:error, :no_plugins_file};
|
2016-10-26 23:25:39 +08:00
|
|
|
file -> {:ok, file}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-08-08 08:21:07 +08:00
|
|
|
def enabled_plugins_file(_, opts) do
|
|
|
|
enabled_plugins_file(opts)
|
|
|
|
end
|
|
|
|
|
2016-12-06 23:12:47 +08:00
|
|
|
def set_enabled_plugins(plugins, opts) do
|
2016-08-11 06:27:13 +08:00
|
|
|
plugin_atoms = :lists.usort(for plugin <- plugins, do: to_atom(plugin))
|
2017-03-10 06:01:03 +08:00
|
|
|
CliHelpers.require_rabbit_and_plugins(opts)
|
2016-06-21 20:54:18 +08:00
|
|
|
{:ok, plugins_file} = enabled_plugins_file(opts)
|
2016-12-06 23:12:47 +08:00
|
|
|
write_enabled_plugins(plugin_atoms, plugins_file, opts)
|
|
|
|
end
|
2016-12-07 00:18:54 +08:00
|
|
|
|
2017-11-28 02:49:08 +08:00
|
|
|
@spec update_enabled_plugins([atom()],
|
|
|
|
:online | :offline | :best_effort,
|
|
|
|
node(),
|
|
|
|
map()) :: map() | {:error, any()}
|
2016-12-06 23:12:47 +08:00
|
|
|
def update_enabled_plugins(enabled_plugins, mode, node_name, opts) do
|
|
|
|
{:ok, plugins_file} = enabled_plugins_file(opts)
|
|
|
|
case mode do
|
2017-11-28 02:49:08 +08:00
|
|
|
:online ->
|
|
|
|
case update_enabled_plugins(node_name, plugins_file) do
|
|
|
|
{:ok, started, stopped} ->
|
|
|
|
%{mode: :online,
|
|
|
|
started: Enum.sort(started),
|
|
|
|
stopped: Enum.sort(stopped),
|
|
|
|
set: Enum.sort(enabled_plugins)};
|
|
|
|
{:error, _} = err -> err
|
|
|
|
end;
|
|
|
|
:best_effort ->
|
2016-12-06 23:12:47 +08:00
|
|
|
case update_enabled_plugins(node_name, plugins_file) do
|
|
|
|
{:ok, started, stopped} ->
|
|
|
|
%{mode: :online,
|
|
|
|
started: Enum.sort(started),
|
|
|
|
stopped: Enum.sort(stopped),
|
|
|
|
set: Enum.sort(enabled_plugins)};
|
|
|
|
{:error, :offline} ->
|
|
|
|
%{mode: :offline, set: Enum.sort(enabled_plugins)};
|
|
|
|
{:error, {:enabled_plugins_mismatch, _, _}} = err ->
|
|
|
|
err
|
2016-06-21 20:54:18 +08:00
|
|
|
end;
|
2016-12-06 23:12:47 +08:00
|
|
|
:offline ->
|
2017-06-12 21:32:40 +08:00
|
|
|
%{mode: :offline,
|
|
|
|
set: Enum.sort(enabled_plugins)}
|
2016-06-21 20:54:18 +08:00
|
|
|
end
|
|
|
|
end
|
2016-12-07 00:18:54 +08:00
|
|
|
|
2017-01-27 00:21:44 +08:00
|
|
|
def validate_plugins(requested_plugins, opts) do
|
|
|
|
## Maybe check all plugins
|
|
|
|
plugins = case opts do
|
|
|
|
%{all: true} -> plugin_names(list(opts))
|
|
|
|
_ -> requested_plugins
|
|
|
|
end
|
|
|
|
|
2017-01-26 20:21:20 +08:00
|
|
|
all = list(opts)
|
|
|
|
deps = :rabbit_plugins.dependencies(false, plugins, all)
|
|
|
|
|
|
|
|
deps_plugins = Enum.filter(all, fn(plugin) ->
|
|
|
|
name = plugin_name(plugin)
|
2017-02-28 23:15:08 +08:00
|
|
|
Enum.member?(deps, name)
|
2017-01-26 20:21:20 +08:00
|
|
|
end)
|
|
|
|
|
|
|
|
case :rabbit_plugins.validate_plugins(deps_plugins) do
|
|
|
|
{_, []} -> :ok;
|
|
|
|
{_, invalid} -> {:error, :rabbit_plugins.format_invalid_plugins(invalid)}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-12-23 00:19:17 +08:00
|
|
|
def plugin_name(plugin) do
|
|
|
|
plugin(name: name) = plugin
|
|
|
|
name
|
|
|
|
end
|
|
|
|
|
2016-12-29 18:45:53 +08:00
|
|
|
def plugin_names(plugins) do
|
|
|
|
for plugin <- plugins, do: plugin_name(plugin)
|
|
|
|
end
|
|
|
|
|
2016-08-11 06:44:27 +08:00
|
|
|
defp to_list(str) when is_binary(str) do
|
|
|
|
:erlang.binary_to_list(str)
|
|
|
|
end
|
2016-08-12 09:46:26 +08:00
|
|
|
|
2016-08-11 06:44:27 +08:00
|
|
|
defp to_list(lst) when is_list(lst) do
|
|
|
|
lst
|
|
|
|
end
|
2016-08-12 09:46:26 +08:00
|
|
|
|
2016-08-11 06:44:27 +08:00
|
|
|
defp to_list(atm) when is_atom(atm) do
|
|
|
|
to_list(Atom.to_string(atm))
|
|
|
|
end
|
|
|
|
|
2016-06-21 20:54:18 +08:00
|
|
|
defp write_enabled_plugins(plugins, plugins_file, opts) do
|
2016-08-11 06:27:13 +08:00
|
|
|
all = list(opts)
|
2016-12-23 00:19:17 +08:00
|
|
|
all_plugin_names = Enum.map(all, &plugin_name/1)
|
2017-08-14 21:36:38 +08:00
|
|
|
missing = MapSet.difference(MapSet.new(plugins), MapSet.new(all_plugin_names))
|
|
|
|
case Enum.empty?(missing) do
|
|
|
|
true ->
|
2017-06-26 18:59:46 +08:00
|
|
|
case :rabbit_file.write_term_file(to_charlist(plugins_file), [plugins]) do
|
2016-06-21 20:54:18 +08:00
|
|
|
:ok ->
|
2016-12-23 00:19:17 +08:00
|
|
|
all_enabled = :rabbit_plugins.dependencies(false, plugins, all)
|
|
|
|
{:ok, Enum.sort(all_enabled)};
|
2016-06-21 20:54:18 +08:00
|
|
|
{:error, reason} ->
|
|
|
|
{:error, {:cannot_write_enabled_plugins_file, plugins_file, reason}}
|
|
|
|
end;
|
2017-08-14 21:36:38 +08:00
|
|
|
false ->
|
|
|
|
{:error, {:plugins_not_found, Enum.to_list(missing)}}
|
2016-06-21 20:54:18 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp update_enabled_plugins(node_name, plugins_file) do
|
|
|
|
case :rabbit_misc.rpc_call(node_name, :rabbit_plugins,
|
2016-08-11 06:44:27 +08:00
|
|
|
:ensure, [to_list(plugins_file)]) do
|
2017-11-28 02:49:08 +08:00
|
|
|
{:badrpc, :nodedown} -> {:error, :offline};
|
|
|
|
{:error, :rabbit_not_running} -> {:error, :offline};
|
2016-06-21 20:54:18 +08:00
|
|
|
{:ok, start, stop} -> {:ok, start, stop};
|
|
|
|
{:error, _} = err -> err
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-11-29 22:26:57 +08:00
|
|
|
defp add_all_to_path(plugins_directories) do
|
|
|
|
directories = String.split(to_string(plugins_directories), CliHelpers.separator())
|
|
|
|
Enum.map(directories, fn(directory) ->
|
|
|
|
with {:ok, subdirs} <- File.ls(directory)
|
|
|
|
do
|
|
|
|
for subdir <- subdirs do
|
|
|
|
Path.join([directory, subdir, "ebin"])
|
|
|
|
|> Code.append_path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
:ok
|
2016-06-20 23:52:36 +08:00
|
|
|
end
|
|
|
|
end
|