rabbitmq-server/deps/rabbitmq_cli/lib/rabbitmq/cli/plugins/plugins_helpers.ex

197 lines
6.1 KiB
Elixir
Raw Normal View History

## 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.
2019-01-20 11:10:59 +08:00
## Copyright (c) 2007-2019 Pivotal Software, Inc. All rights reserved.
2016-11-15 01:52:08 +08:00
alias RabbitMQ.CLI.Core.Helpers, as: CliHelpers
2018-07-23 13:06:18 +08:00
alias RabbitMQ.CLI.Core.{Config, Validators}
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
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
case mode(opts) do
2017-11-28 04:39:14 +08:00
# can always set offline plugins list
:offline -> :ok;
2017-11-28 04:39:14 +08:00
# assume online mode, fall back to offline mode in case of errors
:best_effort -> :ok;
2017-11-28 04:39:14 +08:00
# a running node is required
:online ->
Validators.chain([&Validators.node_is_running/2,
&Validators.rabbit_is_running/2],
[args, opts])
end
end
def list(opts) do
{:ok, dir} = CliHelpers.plugins_dir(opts)
add_all_to_path(dir)
2017-06-26 18:59:46 +08:00
:lists.usort(:rabbit_plugins.list(to_charlist(dir)))
end
def read_enabled(opts) do
case enabled_plugins_file(opts) do
{:ok, enabled} ->
2017-06-26 18:59:46 +08:00
:rabbit_plugins.read_enabled(to_charlist(enabled));
# Existence of enabled_plugins_file should be validated separately
{:error, :no_plugins_file} ->
[]
end
end
def enabled_plugins_file(opts) do
case Config.get_option(:enabled_plugins_file, opts) do
nil -> {:error, :no_plugins_file};
2016-10-26 23:25:39 +08:00
file -> {:ok, file}
end
end
def enabled_plugins_file(_, opts) do
enabled_plugins_file(opts)
end
def set_enabled_plugins(plugins, opts) do
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)
write_enabled_plugins(plugin_atoms, plugins_file, opts)
end
2016-12-07 00:18:54 +08:00
@spec update_enabled_plugins([atom()],
:online | :offline | :best_effort,
node(),
map()) :: map() | {:error, any()}
def update_enabled_plugins(enabled_plugins, mode, node_name, opts) do
{:ok, plugins_file} = enabled_plugins_file(opts)
case mode do
: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 ->
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;
:offline ->
%{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
def validate_plugins(requested_plugins, opts) do
## Maybe check all plugins
plugins = case opts do
%{all: true} -> plugin_names(list(opts))
_ -> requested_plugins
end
all = list(opts)
deps = :rabbit_plugins.dependencies(false, plugins, all)
deps_plugins = Enum.filter(all, fn(plugin) ->
name = plugin_name(plugin)
Enum.member?(deps, name)
end)
case :rabbit_plugins.validate_plugins(deps_plugins) do
{_, []} -> :ok;
{_, invalid} -> {:error, :rabbit_plugins.format_invalid_plugins(invalid)}
end
end
def plugin_name(plugin) do
plugin(name: name) = plugin
name
end
def plugin_names(plugins) do
for plugin <- plugins, do: plugin_name(plugin)
end
defp to_list(str) when is_binary(str) do
:erlang.binary_to_list(str)
end
defp to_list(lst) when is_list(lst) do
lst
end
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
all = list(opts)
all_plugin_names = Enum.map(all, &plugin_name/1)
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 ->
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;
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,
:ensure, [to_list(plugins_file)]) do
{: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
defp add_all_to_path(plugins_directories) do
directories = String.split(to_string(plugins_directories), CliHelpers.path_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
end
end