Format with `gmake format`
This commit is contained in:
		
							parent
							
								
									d29850caef
								
							
						
					
					
						commit
						94b55d71fa
					
				|  | @ -19,6 +19,6 @@ defmodule RabbitCommon.Records do | |||
| 
 | ||||
|   defrecord :amqqueue, extract(:amqqueue, from_lib: "rabbit_common/include/rabbit.hrl") | ||||
|   defrecord :listener, extract(:listener, from_lib: "rabbit_common/include/rabbit.hrl") | ||||
|   defrecord :plugin,   extract(:plugin,   from_lib: "rabbit_common/include/rabbit.hrl") | ||||
|   defrecord :plugin, extract(:plugin, from_lib: "rabbit_common/include/rabbit.hrl") | ||||
|   defrecord :resource, extract(:resource, from_lib: "rabbit_common/include/rabbit.hrl") | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defprotocol Rabbitmq.Atom.Coerce do | ||||
|   def to_atom(data) | ||||
| end | ||||
|  |  | |||
|  | @ -13,19 +13,20 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule Rabbitmq.CLI.AutoComplete do | ||||
|   alias RabbitMQ.CLI.Core.{CommandModules, Parser} | ||||
| 
 | ||||
|   @spec complete(String.t, [String.t]) :: [String.t] | ||||
|   @spec complete(String.t(), [String.t()]) :: [String.t()] | ||||
|   def complete(_, []) do | ||||
|     [] | ||||
|   end | ||||
| 
 | ||||
|   def complete(script_name, args) do | ||||
|     case Parser.parse_global(args) do | ||||
|       {_, %{script_name: _args_script_name}, _} -> | ||||
|         complete(args); | ||||
|       _                                -> | ||||
|         complete(args) | ||||
| 
 | ||||
|       _ -> | ||||
|         complete(["--script-name", script_name | args]) | ||||
|     end | ||||
|   end | ||||
|  | @ -33,45 +34,53 @@ defmodule Rabbitmq.CLI.AutoComplete do | |||
|   defp complete(tokens) do | ||||
|     {command, command_name, _, _, _} = Parser.parse(tokens) | ||||
|     last_token = List.last(tokens) | ||||
| 
 | ||||
|     case {command, command_name} do | ||||
|       ## No command provided | ||||
|       {_, ""} -> complete_default_opts(last_token); | ||||
|       {_, ""} -> | ||||
|         complete_default_opts(last_token) | ||||
| 
 | ||||
|       ## Command is not found/incomplete | ||||
|       {:no_command, command_name} -> | ||||
|         complete_command_name(command_name); | ||||
|         complete_command_name(command_name) | ||||
| 
 | ||||
|       {{:suggest, _}, command_name} -> | ||||
|         complete_command_name(command_name); | ||||
|         complete_command_name(command_name) | ||||
| 
 | ||||
|       ## Command is found | ||||
|       {command, _} -> | ||||
|         complete_command_opts(command, last_token) | ||||
|     end | ||||
|     |> Enum.sort | ||||
|     |> Enum.sort() | ||||
|   end | ||||
| 
 | ||||
|   defp complete_default_opts(opt) do | ||||
|     Parser.default_switches | ||||
|     |> Keyword.keys | ||||
|     |> Enum.map(fn(sw) -> "--" <> to_string(sw) end) | ||||
|     Parser.default_switches() | ||||
|     |> Keyword.keys() | ||||
|     |> Enum.map(fn sw -> "--" <> to_string(sw) end) | ||||
|     |> select_starts_with(opt) | ||||
|     |> format_options | ||||
|   end | ||||
| 
 | ||||
|   defp complete_command_name(command_name) do | ||||
|     module_map = CommandModules.module_map | ||||
|     module_map = CommandModules.module_map() | ||||
| 
 | ||||
|     case module_map[command_name] do | ||||
|       nil -> | ||||
|         module_map | ||||
|         |> Map.keys | ||||
|         |> Map.keys() | ||||
|         |> select_starts_with(command_name) | ||||
| 
 | ||||
|       _ -> | ||||
|         command_name | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   defp complete_command_opts(command, <<"-", _ :: binary>> = opt) do | ||||
|     switches = command.switches | ||||
|                |> Keyword.keys | ||||
|                |> Enum.map(fn(sw) -> "--" <> to_string(sw) end) | ||||
|   defp complete_command_opts(command, <<"-", _::binary>> = opt) do | ||||
|     switches = | ||||
|       command.switches | ||||
|       |> Keyword.keys() | ||||
|       |> Enum.map(fn sw -> "--" <> to_string(sw) end) | ||||
| 
 | ||||
|     # aliases = command.aliases | ||||
|     #           |> Keyword.keys | ||||
|  | @ -79,16 +88,17 @@ defmodule Rabbitmq.CLI.AutoComplete do | |||
|     select_starts_with(switches, opt) | ||||
|     |> format_options | ||||
|   end | ||||
| 
 | ||||
|   defp complete_command_opts(_, _) do | ||||
|     [] | ||||
|   end | ||||
| 
 | ||||
|   defp select_starts_with(list, prefix) do | ||||
|     Enum.filter(list, fn(el) -> String.starts_with?(el, prefix) end) | ||||
|     Enum.filter(list, fn el -> String.starts_with?(el, prefix) end) | ||||
|   end | ||||
| 
 | ||||
|   defp format_options(options) do | ||||
|     options | ||||
|     |> Enum.map(fn(opt) -> String.replace(opt, "_", "-") end) | ||||
|     |> Enum.map(fn opt -> String.replace(opt, "_", "-") end) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,19 +13,21 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.CommandBehaviour do | ||||
|   @callback usage() :: String.t | [String.t] | ||||
|   @callback usage() :: String.t() | [String.t()] | ||||
|   # validates CLI arguments | ||||
|   @callback validate(list(), map()) :: :ok | {:validation_failure, atom() | {atom(), String.t}} | ||||
|   @callback validate(list(), map()) :: :ok | {:validation_failure, atom() | {atom(), String.t()}} | ||||
|   @callback merge_defaults(list(), map()) :: {list(), map()} | ||||
|   @callback banner(list(), map()) :: [String.t] | String.t | nil | ||||
|   @callback banner(list(), map()) :: [String.t()] | String.t() | nil | ||||
|   @callback run(list(), map()) :: any | ||||
|   # Coerces run/2 return value into the standard command output form | ||||
|   # that is then formatted, printed and returned as an exit code. | ||||
|   # There is a default implementation for this callback in DefaultOutput module | ||||
|   @callback output(any, map()) :: :ok | {:ok, any} | {:stream, Enum.t} | | ||||
|                                   {:error, RabbitMQ.CLI.Core.ExitCodes.exit_code, [String.t]} | ||||
|   @callback output(any, map()) :: | ||||
|               :ok | ||||
|               | {:ok, any} | ||||
|               | {:stream, Enum.t()} | ||||
|               | {:error, RabbitMQ.CLI.Core.ExitCodes.exit_code(), [String.t()]} | ||||
|   @optional_callbacks formatter: 0, | ||||
|                       scopes: 0, | ||||
|                       usage_additional: 0, | ||||
|  | @ -36,16 +38,17 @@ defmodule RabbitMQ.CLI.CommandBehaviour do | |||
|                       validate_execution_environment: 2, | ||||
|                       distribution: 1 | ||||
| 
 | ||||
|   @callback validate_execution_environment(list(), map()) :: :ok | {:validation_failure, atom() | {atom(), any}} | ||||
|   @callback switches() :: Keyword.t | ||||
|   @callback aliases() :: Keyword.t | ||||
|   @callback validate_execution_environment(list(), map()) :: | ||||
|               :ok | {:validation_failure, atom() | {atom(), any}} | ||||
|   @callback switches() :: Keyword.t() | ||||
|   @callback aliases() :: Keyword.t() | ||||
| 
 | ||||
|   @callback formatter() :: atom() | ||||
|   @callback scopes() :: [atom()] | ||||
|   @callback usage_additional() :: String.t | [String.t] | ||||
|   @callback usage_additional() :: String.t() | [String.t()] | ||||
|   ## Erlang distribution control | ||||
|   ## :cli - default rabbitmqctl generated node name | ||||
|   ## :none - disable erlang distribution | ||||
|   ## {:fun, fun} - use a custom function to start distribution | ||||
|   @callback distribution(map()) :: :cli | :none | {:fun, ((map()) -> :ok | {:error, any()})} | ||||
|   @callback distribution(map()) :: :cli | :none | {:fun, (map() -> :ok | {:error, any()})} | ||||
| end | ||||
|  |  | |||
|  | @ -19,8 +19,9 @@ defmodule RabbitMQ.CLI.Core.AcceptsNoPositionalArguments do | |||
|   defmacro __using__(_) do | ||||
|     quote do | ||||
|       def validate(args, _) when length(args) > 0 do | ||||
|           {:validation_failure, :too_many_args} | ||||
|         {:validation_failure, :too_many_args} | ||||
|       end | ||||
| 
 | ||||
|       # Note: this will accept everything, so it must be the | ||||
|       # last validation clause defined! | ||||
|       def validate(_, _), do: :ok | ||||
|  |  | |||
|  | @ -19,11 +19,13 @@ defmodule RabbitMQ.CLI.Core.AcceptsOnePositionalArgument do | |||
|   defmacro __using__(_) do | ||||
|     quote do | ||||
|       def validate(args, _) when length(args) == 0 do | ||||
|           {:validation_failure, :not_enough_args} | ||||
|         {:validation_failure, :not_enough_args} | ||||
|       end | ||||
| 
 | ||||
|       def validate(args, _) when length(args) > 1 do | ||||
|           {:validation_failure, :too_many_args} | ||||
|         {:validation_failure, :too_many_args} | ||||
|       end | ||||
| 
 | ||||
|       # Note: this will accept everything, so it must be the | ||||
|       # last validation clause defined! | ||||
|       def validate(_, _), do: :ok | ||||
|  |  | |||
|  | @ -19,21 +19,24 @@ defmodule RabbitMQ.CLI.Core.AcceptsOnePositiveIntegerArgument do | |||
|   defmacro __using__(_) do | ||||
|     quote do | ||||
|       def validate(args, _) when length(args) == 0 do | ||||
|           {:validation_failure, :not_enough_args} | ||||
|         {:validation_failure, :not_enough_args} | ||||
|       end | ||||
| 
 | ||||
|       def validate(args, _) when length(args) > 1 do | ||||
|           {:validation_failure, :too_many_args} | ||||
|         {:validation_failure, :too_many_args} | ||||
|       end | ||||
| 
 | ||||
|       def validate([value], _) when is_integer(value) do | ||||
|         :ok | ||||
|       end | ||||
| 
 | ||||
|       def validate([value], _) do | ||||
|           case Integer.parse(value) do | ||||
|             {n, _} when n >= 1 -> :ok | ||||
|             :error             -> {:validation_failure, | ||||
|                                     {:bad_argument, "Argument must be a positive integer"}} | ||||
|           end | ||||
|         case Integer.parse(value) do | ||||
|           {n, _} when n >= 1 -> :ok | ||||
|           :error -> {:validation_failure, {:bad_argument, "Argument must be a positive integer"}} | ||||
|         end | ||||
|       end | ||||
| 
 | ||||
|       def validate(_, _), do: :ok | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -60,25 +60,31 @@ defmodule RabbitMQ.CLI.Core.CommandModules do | |||
| 
 | ||||
|   def plugin_modules(opts) do | ||||
|     Helpers.require_rabbit(opts) | ||||
| 
 | ||||
|     enabled_plugins = | ||||
|       try do | ||||
|         PluginsHelpers.read_enabled(opts) | ||||
|       catch err -> | ||||
|         {:ok, enabled_plugins_file} = PluginsHelpers.enabled_plugins_file(opts) | ||||
|         require Logger | ||||
|         Logger.warn("Unable to read the enebled plugins file.\n" <> | ||||
|                     "  Reason: #{inspect(err)}\n" <> | ||||
|                     "  Commands provided by plugins will not be available.\n" <> | ||||
|                     "  Please make sure your user has sufficient permissions to read to\n" <> | ||||
|                     "    #{enabled_plugins_file}") | ||||
|         [] | ||||
|       catch | ||||
|         err -> | ||||
|           {:ok, enabled_plugins_file} = PluginsHelpers.enabled_plugins_file(opts) | ||||
|           require Logger | ||||
| 
 | ||||
|           Logger.warn( | ||||
|             "Unable to read the enebled plugins file.\n" <> | ||||
|               "  Reason: #{inspect(err)}\n" <> | ||||
|               "  Commands provided by plugins will not be available.\n" <> | ||||
|               "  Please make sure your user has sufficient permissions to read to\n" <> | ||||
|               "    #{enabled_plugins_file}" | ||||
|           ) | ||||
| 
 | ||||
|           [] | ||||
|       end | ||||
| 
 | ||||
|     partitioned = | ||||
|       Enum.group_by(enabled_plugins, fn(app) -> | ||||
|       Enum.group_by(enabled_plugins, fn app -> | ||||
|         case Application.load(app) do | ||||
|           :ok -> :loaded; | ||||
|           {:error, {:already_loaded, ^app}} -> :loaded; | ||||
|           :ok -> :loaded | ||||
|           {:error, {:already_loaded, ^app}} -> :loaded | ||||
|           _ -> :not_found | ||||
|         end | ||||
|       end) | ||||
|  | @ -87,36 +93,37 @@ defmodule RabbitMQ.CLI.Core.CommandModules do | |||
|     missing = partitioned[:not_found] || [] | ||||
|     ## If plugins are not in ERL_LIBS, they should be loaded from plugins_dir | ||||
|     case missing do | ||||
|       [] -> :ok; | ||||
|       _  -> | ||||
|       [] -> | ||||
|         :ok | ||||
| 
 | ||||
|       _ -> | ||||
|         Helpers.add_plugins_to_load_path(opts) | ||||
|         Enum.each(missing, fn(app) -> Application.load(app) end) | ||||
|         Enum.each(missing, fn app -> Application.load(app) end) | ||||
|     end | ||||
| 
 | ||||
|     Enum.flat_map(loaded ++ missing, fn(app) -> | ||||
|     Enum.flat_map(loaded ++ missing, fn app -> | ||||
|       Application.spec(app, :modules) || [] | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
|   defp make_module_map(modules, scope) do | ||||
|     commands_ns = Regex.recompile!(@commands_ns) | ||||
| 
 | ||||
|     modules | ||||
|     |> Enum.filter(fn(mod) -> | ||||
|                      to_string(mod) =~ commands_ns | ||||
|                      and | ||||
|                      module_exists?(mod) | ||||
|                      and | ||||
|                      implements_command_behaviour?(mod) | ||||
|                      and | ||||
|                      command_in_scope(mod, scope) | ||||
|                    end) | ||||
|     |> Enum.filter(fn mod -> | ||||
|       to_string(mod) =~ commands_ns and | ||||
|         module_exists?(mod) and | ||||
|         implements_command_behaviour?(mod) and | ||||
|         command_in_scope(mod, scope) | ||||
|     end) | ||||
|     |> Enum.map(&command_tuple/1) | ||||
|     |> Map.new | ||||
|     |> Map.new() | ||||
|   end | ||||
| 
 | ||||
|   defp module_exists?(nil) do | ||||
|     false | ||||
|   end | ||||
| 
 | ||||
|   defp module_exists?(mod) do | ||||
|     Code.ensure_loaded?(mod) | ||||
|   end | ||||
|  | @ -124,9 +131,12 @@ defmodule RabbitMQ.CLI.Core.CommandModules do | |||
|   defp implements_command_behaviour?(nil) do | ||||
|     false | ||||
|   end | ||||
| 
 | ||||
|   defp implements_command_behaviour?(module) do | ||||
|     Enum.member?(module.module_info(:attributes)[:behaviour] || [], | ||||
|                  RabbitMQ.CLI.CommandBehaviour) | ||||
|     Enum.member?( | ||||
|       module.module_info(:attributes)[:behaviour] || [], | ||||
|       RabbitMQ.CLI.CommandBehaviour | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def module_to_command(mod) do | ||||
|  | @ -144,16 +154,16 @@ defmodule RabbitMQ.CLI.Core.CommandModules do | |||
|   def strip_namespace(str) do | ||||
|     str | ||||
|     |> String.split(".") | ||||
|     |> List.last | ||||
|     |> List.last() | ||||
|   end | ||||
| 
 | ||||
|   def to_snake_case(<<c, str :: binary>>) do | ||||
|   def to_snake_case(<<c, str::binary>>) do | ||||
|     tail = for <<c <- str>>, into: "", do: snake(c) | ||||
|     <<to_lower_char(c), tail :: binary >> | ||||
|     <<to_lower_char(c), tail::binary>> | ||||
|   end | ||||
| 
 | ||||
|   defp snake(c) do | ||||
|     if (c >= ?A) and (c <= ?Z) do | ||||
|     if c >= ?A and c <= ?Z do | ||||
|       <<"_", c + 32>> | ||||
|     else | ||||
|       <<c>> | ||||
|  | @ -161,7 +171,7 @@ defmodule RabbitMQ.CLI.Core.CommandModules do | |||
|   end | ||||
| 
 | ||||
|   defp to_lower_char(c) do | ||||
|     if (c >= ?A) and (c <= ?Z) do | ||||
|     if c >= ?A and c <= ?Z do | ||||
|       c + 32 | ||||
|     else | ||||
|       c | ||||
|  | @ -171,21 +181,23 @@ defmodule RabbitMQ.CLI.Core.CommandModules do | |||
|   defp command_in_scope(_cmd, :all) do | ||||
|     true | ||||
|   end | ||||
| 
 | ||||
|   defp command_in_scope(cmd, scope) do | ||||
|     Enum.member?(command_scopes(cmd), scope) | ||||
|   end | ||||
| 
 | ||||
|   defp command_scopes(cmd) do | ||||
|     case :erlang.function_exported(cmd, :scopes, 0) do | ||||
|       true  -> | ||||
|       true -> | ||||
|         cmd.scopes() | ||||
| 
 | ||||
|       false -> | ||||
|         Regex.recompile!(@commands_ns) | ||||
|         |> Regex.run(to_string(cmd), capture: :all_but_first) | ||||
|         |> List.first | ||||
|         |> List.first() | ||||
|         |> to_snake_case | ||||
|         |> String.to_atom | ||||
|         |> List.wrap | ||||
|         |> String.to_atom() | ||||
|         |> List.wrap() | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -14,15 +14,16 @@ | |||
| ## Copyright (c) 2016-2017 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Core.Config do | ||||
| 
 | ||||
|   # | ||||
|   # Environment | ||||
|   # | ||||
| 
 | ||||
|   def get_option(name, opts \\ %{}) do | ||||
|     raw_option = opts[name] || | ||||
|                    get_system_option(name) || | ||||
|                    default(name) | ||||
|     raw_option = | ||||
|       opts[name] || | ||||
|         get_system_option(name) || | ||||
|         default(name) | ||||
| 
 | ||||
|     normalise(name, raw_option) | ||||
|   end | ||||
| 
 | ||||
|  | @ -31,46 +32,51 @@ defmodule RabbitMQ.CLI.Core.Config do | |||
|   end | ||||
| 
 | ||||
|   def normalise(:node, nil), do: nil | ||||
| 
 | ||||
|   def normalise(:node, node) when not is_atom(node) do | ||||
|     Rabbitmq.Atom.Coerce.to_atom(node) | ||||
|   end | ||||
| 
 | ||||
|   def normalise(:erlang_cookie, nil), do: nil | ||||
| 
 | ||||
|   def normalise(:erlang_cookie, c) when not is_atom(c) do | ||||
|     Rabbitmq.Atom.Coerce.to_atom(c) | ||||
|   end | ||||
|   def normalise(:longnames, true),       do: :longnames | ||||
|   def normalise(:longnames, "true"),     do: :longnames | ||||
|   def normalise(:longnames, 'true'),     do: :longnames | ||||
| 
 | ||||
|   def normalise(:longnames, true), do: :longnames | ||||
|   def normalise(:longnames, "true"), do: :longnames | ||||
|   def normalise(:longnames, 'true'), do: :longnames | ||||
|   def normalise(:longnames, "\"true\""), do: :longnames | ||||
|   def normalise(:longnames, _val),       do: :shortnames | ||||
|   def normalise(_, value),               do: value | ||||
|   def normalise(:longnames, _val), do: :shortnames | ||||
|   def normalise(_, value), do: value | ||||
| 
 | ||||
|   def system_env_variable(name) do | ||||
|     case name do | ||||
|       :longnames            -> "RABBITMQ_USE_LONGNAME"; | ||||
|       :rabbitmq_home        -> "RABBITMQ_HOME"; | ||||
|       :mnesia_dir           -> "RABBITMQ_MNESIA_DIR"; | ||||
|       :plugins_dir          -> "RABBITMQ_PLUGINS_DIR"; | ||||
|       :plugins_expand_dir   -> "RABBITMQ_PLUGINS_EXPAND_DIR"; | ||||
|       :enabled_plugins_file -> "RABBITMQ_ENABLED_PLUGINS_FILE"; | ||||
|       :node                 -> "RABBITMQ_NODENAME"; | ||||
|       :aliases_file         -> "RABBITMQ_CLI_ALIASES_FILE"; | ||||
|       :erlang_cookie        -> "RABBITMQ_ERLANG_COOKIE"; | ||||
|       :longnames -> "RABBITMQ_USE_LONGNAME" | ||||
|       :rabbitmq_home -> "RABBITMQ_HOME" | ||||
|       :mnesia_dir -> "RABBITMQ_MNESIA_DIR" | ||||
|       :plugins_dir -> "RABBITMQ_PLUGINS_DIR" | ||||
|       :plugins_expand_dir -> "RABBITMQ_PLUGINS_EXPAND_DIR" | ||||
|       :enabled_plugins_file -> "RABBITMQ_ENABLED_PLUGINS_FILE" | ||||
|       :node -> "RABBITMQ_NODENAME" | ||||
|       :aliases_file -> "RABBITMQ_CLI_ALIASES_FILE" | ||||
|       :erlang_cookie -> "RABBITMQ_ERLANG_COOKIE" | ||||
|       _ -> "" | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def get_system_option(:script_name) do | ||||
|     Path.basename(:escript.script_name()) | ||||
|     |> Path.rootname | ||||
|     |> String.to_atom | ||||
|     |> Path.rootname() | ||||
|     |> String.to_atom() | ||||
|   end | ||||
| 
 | ||||
|   def get_system_option(name) do | ||||
|     System.get_env(system_env_variable(name)) | ||||
|   end | ||||
| 
 | ||||
|   def default(:script_name), do: :rabbitmqctl | ||||
|   def default(:node),        do: :rabbit | ||||
|   def default(:node), do: :rabbit | ||||
|   def default(_), do: nil | ||||
| 
 | ||||
|   # | ||||
|  | @ -79,22 +85,26 @@ defmodule RabbitMQ.CLI.Core.Config do | |||
| 
 | ||||
|   def get_formatter(command, %{formatter: formatter}) do | ||||
|     module_name = Module.safe_concat("RabbitMQ.CLI.Formatters", Macro.camelize(formatter)) | ||||
| 
 | ||||
|     case Code.ensure_loaded(module_name) do | ||||
|       {:module, _}      -> module_name; | ||||
|       {:module, _} -> module_name | ||||
|       {:error, :nofile} -> default_formatter(command) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def get_formatter(command, _) do | ||||
|     default_formatter(command) | ||||
|   end | ||||
| 
 | ||||
|   def get_printer(%{printer: printer}) do | ||||
|     module_name = String.to_atom("RabbitMQ.CLI.Printers." <> Macro.camelize(printer)) | ||||
| 
 | ||||
|     case Code.ensure_loaded(module_name) do | ||||
|       {:module, _}      -> module_name; | ||||
|       {:module, _} -> module_name | ||||
|       {:error, :nofile} -> default_printer() | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def get_printer(_) do | ||||
|     default_printer() | ||||
|   end | ||||
|  | @ -105,9 +115,8 @@ defmodule RabbitMQ.CLI.Core.Config do | |||
| 
 | ||||
|   def default_formatter(command) do | ||||
|     case function_exported?(command, :formatter, 0) do | ||||
|       true  -> command.formatter; | ||||
|       true -> command.formatter | ||||
|       false -> RabbitMQ.CLI.Formatters.String | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -37,25 +37,24 @@ defmodule RabbitMQ.CLI.Core.ExitCodes do | |||
|   def exit_tempfail, do: @exit_tempfail | ||||
|   def exit_config, do: @exit_config | ||||
| 
 | ||||
|   def exit_code_for({:validation_failure, :not_enough_args}),      do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, :too_many_args}),        do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, :not_enough_args}), do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, :too_many_args}), do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, {:not_enough_args, _}}), do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, {:too_many_args, _}}),   do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, {:bad_argument, _}}),    do: exit_dataerr() | ||||
|   def exit_code_for({:validation_failure, :bad_argument}),         do: exit_dataerr() | ||||
|   def exit_code_for({:validation_failure, :eperm}),                do: exit_dataerr() | ||||
|   def exit_code_for({:validation_failure, {:bad_option, _}}),      do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, _}),                     do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, {:too_many_args, _}}), do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, {:bad_argument, _}}), do: exit_dataerr() | ||||
|   def exit_code_for({:validation_failure, :bad_argument}), do: exit_dataerr() | ||||
|   def exit_code_for({:validation_failure, :eperm}), do: exit_dataerr() | ||||
|   def exit_code_for({:validation_failure, {:bad_option, _}}), do: exit_usage() | ||||
|   def exit_code_for({:validation_failure, _}), do: exit_usage() | ||||
|   # a special case of bad_argument | ||||
|   def exit_code_for({:no_such_vhost, _}),       do: exit_dataerr() | ||||
|   def exit_code_for({:badrpc_multi, :timeout, _}),       do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc, :timeout}),       do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc, {:timeout, _}}),  do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc, {:timeout, _, _}}),  do: exit_tempfail() | ||||
|   def exit_code_for(:timeout),                  do: exit_tempfail() | ||||
|   def exit_code_for({:timeout, _}),             do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc_multi, :nodedown, _}),      do: exit_unavailable() | ||||
|   def exit_code_for({:badrpc, :nodedown}),      do: exit_unavailable() | ||||
|   def exit_code_for({:error, _}),               do: exit_unavailable() | ||||
| 
 | ||||
|   def exit_code_for({:no_such_vhost, _}), do: exit_dataerr() | ||||
|   def exit_code_for({:badrpc_multi, :timeout, _}), do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc, :timeout}), do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc, {:timeout, _}}), do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc, {:timeout, _, _}}), do: exit_tempfail() | ||||
|   def exit_code_for(:timeout), do: exit_tempfail() | ||||
|   def exit_code_for({:timeout, _}), do: exit_tempfail() | ||||
|   def exit_code_for({:badrpc_multi, :nodedown, _}), do: exit_unavailable() | ||||
|   def exit_code_for({:badrpc, :nodedown}), do: exit_unavailable() | ||||
|   def exit_code_for({:error, _}), do: exit_unavailable() | ||||
| end | ||||
|  |  | |||
|  | @ -45,10 +45,11 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
| 
 | ||||
|   def validate_step(:ok, step) do | ||||
|     case step.() do | ||||
|       {:error, err} -> {:validation_failure, err}; | ||||
|       _             -> :ok | ||||
|       {:error, err} -> {:validation_failure, err} | ||||
|       _ -> :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def validate_step({:validation_failure, err}, _) do | ||||
|     {:validation_failure, err} | ||||
|   end | ||||
|  | @ -57,31 +58,32 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
|     ["k", "kiB", "M", "MiB", "G", "GiB", "kB", "MB", "GB", ""] | ||||
|   end | ||||
| 
 | ||||
|   def memory_unit_absolute(num, unit) when is_number(num) and num < 0, do: {:bad_argument, [num, unit]} | ||||
|   def memory_unit_absolute(num, unit) when is_number(num) and num < 0, | ||||
|     do: {:bad_argument, [num, unit]} | ||||
| 
 | ||||
|   def memory_unit_absolute(num, "k") when is_number(num),   do: power_as_int(num, 2, 10) | ||||
|   def memory_unit_absolute(num, "k") when is_number(num), do: power_as_int(num, 2, 10) | ||||
|   def memory_unit_absolute(num, "kiB") when is_number(num), do: power_as_int(num, 2, 10) | ||||
|   def memory_unit_absolute(num, "M") when is_number(num),   do: power_as_int(num, 2, 20) | ||||
|   def memory_unit_absolute(num, "M") when is_number(num), do: power_as_int(num, 2, 20) | ||||
|   def memory_unit_absolute(num, "MiB") when is_number(num), do: power_as_int(num, 2, 20) | ||||
|   def memory_unit_absolute(num, "G") when is_number(num),   do: power_as_int(num, 2, 30) | ||||
|   def memory_unit_absolute(num, "G") when is_number(num), do: power_as_int(num, 2, 30) | ||||
|   def memory_unit_absolute(num, "GiB") when is_number(num), do: power_as_int(num, 2, 30) | ||||
|   def memory_unit_absolute(num, "kB") when is_number(num),  do: power_as_int(num, 10, 3) | ||||
|   def memory_unit_absolute(num, "MB") when is_number(num),  do: power_as_int(num, 10, 6) | ||||
|   def memory_unit_absolute(num, "GB") when is_number(num),  do: power_as_int(num, 10, 9) | ||||
|   def memory_unit_absolute(num, "kB") when is_number(num), do: power_as_int(num, 10, 3) | ||||
|   def memory_unit_absolute(num, "MB") when is_number(num), do: power_as_int(num, 10, 6) | ||||
|   def memory_unit_absolute(num, "GB") when is_number(num), do: power_as_int(num, 10, 9) | ||||
|   def memory_unit_absolute(num, "") when is_number(num), do: num | ||||
|   def memory_unit_absolute(num, unit) when is_number(num), do: {:bad_argument, [unit]} | ||||
|   def memory_unit_absolute(num, unit), do: {:bad_argument, [num, unit]} | ||||
| 
 | ||||
|   def power_as_int(num, x, y), do: round(num * (:math.pow(x, y))) | ||||
|   def power_as_int(num, x, y), do: round(num * :math.pow(x, y)) | ||||
| 
 | ||||
|   def nodes_in_cluster(node, timeout \\ :infinity) do | ||||
|     with_nodes_in_cluster(node, fn(nodes) -> nodes end, timeout) | ||||
|     with_nodes_in_cluster(node, fn nodes -> nodes end, timeout) | ||||
|   end | ||||
| 
 | ||||
|   def with_nodes_in_cluster(node, fun, timeout \\ :infinity) do | ||||
|     case :rpc.call(node, :rabbit_mnesia, :cluster_nodes, [:running], timeout) do | ||||
|       {:badrpc, _} = err -> err | ||||
|       value              -> fun.(value) | ||||
|       value -> fun.(value) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -91,11 +93,14 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
| 
 | ||||
|   def plugins_dir(opts) do | ||||
|     case Config.get_option(:plugins_dir, opts) do | ||||
|       nil -> {:error, :no_plugins_dir}; | ||||
|       nil -> | ||||
|         {:error, :no_plugins_dir} | ||||
| 
 | ||||
|       dir -> | ||||
|         paths = String.split(to_string(dir), path_separator()) | ||||
| 
 | ||||
|         case Enum.any?(paths, &File.dir?/1) do | ||||
|           true  -> {:ok, dir}; | ||||
|           true -> {:ok, dir} | ||||
|           false -> {:error, :plugins_dir_does_not_exist} | ||||
|         end | ||||
|     end | ||||
|  | @ -117,19 +122,24 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
| 
 | ||||
|   def require_rabbit(opts) do | ||||
|     home = Config.get_option(:rabbitmq_home, opts) | ||||
| 
 | ||||
|     case home do | ||||
|       nil -> | ||||
|         {:error, {:unable_to_load_rabbit, :rabbitmq_home_is_undefined}}; | ||||
|       _   -> | ||||
|         {:error, {:unable_to_load_rabbit, :rabbitmq_home_is_undefined}} | ||||
| 
 | ||||
|       _ -> | ||||
|         path = Path.join(home, "ebin") | ||||
|         Code.append_path(path) | ||||
| 
 | ||||
|         case Application.load(:rabbit) do | ||||
|           :ok -> | ||||
|             Code.ensure_loaded(:rabbit_plugins) | ||||
|             :ok; | ||||
|             :ok | ||||
| 
 | ||||
|           {:error, {:already_loaded, :rabbit}} -> | ||||
|             Code.ensure_loaded(:rabbit_plugins) | ||||
|             :ok; | ||||
|             :ok | ||||
| 
 | ||||
|           {:error, err} -> | ||||
|             {:error, {:unable_to_load_rabbit, err}} | ||||
|         end | ||||
|  | @ -138,7 +148,7 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
| 
 | ||||
|   def rabbit_app_running?(%{node: node, timeout: timeout}) do | ||||
|     case :rabbit_misc.rpc_call(node, :rabbit, :is_running, [], timeout) do | ||||
|       true  -> true | ||||
|       true -> true | ||||
|       false -> false | ||||
|       other -> {:error, other} | ||||
|     end | ||||
|  | @ -149,32 +159,34 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
|   end | ||||
| 
 | ||||
|   def add_plugins_to_load_path(opts) do | ||||
|     with {:ok, plugins_dir} <- plugins_dir(opts) | ||||
|     do | ||||
|     with {:ok, plugins_dir} <- plugins_dir(opts) do | ||||
|       String.split(to_string(plugins_dir), path_separator()) | ||||
|       |> | ||||
|       Enum.map(&add_directory_plugins_to_load_path/1) | ||||
|       |> Enum.map(&add_directory_plugins_to_load_path/1) | ||||
| 
 | ||||
|       :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def add_directory_plugins_to_load_path(directory_with_plugins_inside_it) do | ||||
|     with {:ok, files} <- File.ls(directory_with_plugins_inside_it) | ||||
|     do | ||||
|       Enum.map(files, | ||||
|         fn(filename) -> | ||||
|     with {:ok, files} <- File.ls(directory_with_plugins_inside_it) do | ||||
|       Enum.map( | ||||
|         files, | ||||
|         fn filename -> | ||||
|           cond do | ||||
|             String.ends_with?(filename, [".ez"]) -> | ||||
|               Path.join([directory_with_plugins_inside_it, filename]) | ||||
|               |> String.to_charlist | ||||
|               |> add_archive_code_path(); | ||||
|               |> String.to_charlist() | ||||
|               |> add_archive_code_path() | ||||
| 
 | ||||
|             File.dir?(filename) -> | ||||
|               Path.join([directory_with_plugins_inside_it, filename]) | ||||
|               |> add_dir_code_path(); | ||||
|               |> add_dir_code_path() | ||||
| 
 | ||||
|             true -> | ||||
|               {:error, {:not_a_plugin, filename}} | ||||
|           end | ||||
|         end) | ||||
|         end | ||||
|       ) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -182,22 +194,29 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
|     case :erl_prim_loader.list_dir(ez_dir) do | ||||
|       {:ok, [app_dir]} -> | ||||
|         app_in_ez = :filename.join(ez_dir, app_dir) | ||||
|         add_dir_code_path(app_in_ez); | ||||
|       _ -> {:error, :no_app_dir} | ||||
|         add_dir_code_path(app_in_ez) | ||||
| 
 | ||||
|       _ -> | ||||
|         {:error, :no_app_dir} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   defp add_dir_code_path(app_dir_0) do | ||||
|     app_dir = to_charlist(app_dir_0) | ||||
| 
 | ||||
|     case :erl_prim_loader.list_dir(app_dir) do | ||||
|       {:ok, list} -> | ||||
|         case Enum.member?(list, 'ebin') do | ||||
|           true -> | ||||
|             ebin_dir = :filename.join(app_dir, 'ebin') | ||||
|             Code.append_path(ebin_dir) | ||||
|           false -> {:error, :no_ebin} | ||||
|         end; | ||||
|       _ -> {:error, :app_dir_empty} | ||||
| 
 | ||||
|           false -> | ||||
|             {:error, :no_ebin} | ||||
|         end | ||||
| 
 | ||||
|       _ -> | ||||
|         {:error, :app_dir_empty} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -205,10 +224,12 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
|     case Application.get_env(:mnesia, :dir) do | ||||
|       nil -> | ||||
|         case Config.get_option(:mnesia_dir, opts) do | ||||
|           nil -> {:error, :mnesia_dir_not_found}; | ||||
|           nil -> {:error, :mnesia_dir_not_found} | ||||
|           val -> Application.put_env(:mnesia, :dir, to_charlist(val)) | ||||
|         end | ||||
|       _   -> :ok | ||||
| 
 | ||||
|       _ -> | ||||
|         :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -218,7 +239,7 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
| 
 | ||||
|   # Convert function to stream | ||||
|   def defer(fun) do | ||||
|     Stream.iterate(:ok, fn(_) -> fun.() end) | ||||
|     Stream.iterate(:ok, fn _ -> fun.() end) | ||||
|     |> Stream.drop(1) | ||||
|     |> Stream.take(1) | ||||
|   end | ||||
|  | @ -230,18 +251,18 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
|   # to then next function, or {:ok, val, output} where | ||||
|   # val will be passed and output will be put into the stream | ||||
|   def stream_until_error_parametrised(funs, init) do | ||||
|     Stream.transform( | ||||
|       funs, {:just, init}, | ||||
|       fn(f, {:just, val}) -> | ||||
|           case f.(val) do | ||||
|             {:error, _} = err -> {[err], :nothing}; | ||||
|             :ok               -> {[], {:just, val}}; | ||||
|             {:ok, new_val}        -> {[], {:just, new_val}}; | ||||
|             {:ok, new_val, out}   -> {[out], {:just, new_val}} | ||||
|           end; | ||||
|         (_, :nothing) -> | ||||
|           {:halt, :nothing} | ||||
|       end) | ||||
|     Stream.transform(funs, {:just, init}, fn | ||||
|       f, {:just, val} -> | ||||
|         case f.(val) do | ||||
|           {:error, _} = err -> {[err], :nothing} | ||||
|           :ok -> {[], {:just, val}} | ||||
|           {:ok, new_val} -> {[], {:just, new_val}} | ||||
|           {:ok, new_val, out} -> {[out], {:just, new_val}} | ||||
|         end | ||||
| 
 | ||||
|       _, :nothing -> | ||||
|         {:halt, :nothing} | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
|   # Streamify function sequence. | ||||
|  | @ -251,35 +272,37 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
|     stream_until_error_parametrised( | ||||
|       Enum.map( | ||||
|         funs, | ||||
|         fn(fun) -> | ||||
|           fn(:no_param) -> | ||||
|         fn fun -> | ||||
|           fn :no_param -> | ||||
|             case fun.() do | ||||
|               {:error, _} = err -> err; | ||||
|               other             -> {:ok, :no_param, other} | ||||
|               {:error, _} = err -> err | ||||
|               other -> {:ok, :no_param, other} | ||||
|             end | ||||
|           end | ||||
|         end), | ||||
|       :no_param) | ||||
|         end | ||||
|       ), | ||||
|       :no_param | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def apply_if_exported(mod, fun, args, default) do | ||||
|     case function_exported?(mod, fun, length(args)) do | ||||
|       true  -> apply(mod, fun, args); | ||||
|       true -> apply(mod, fun, args) | ||||
|       false -> default | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def path_separator() do | ||||
|     case :os.type do | ||||
|         {:unix, _} ->  ":" | ||||
|         {:win32, _} -> ";" | ||||
|     case :os.type() do | ||||
|       {:unix, _} -> ":" | ||||
|       {:win32, _} -> ";" | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def line_separator() do | ||||
|     case :os.type do | ||||
|         {:unix, _} ->  "\n" | ||||
|         {:win32, _} -> "\r\n" | ||||
|     case :os.type() do | ||||
|       {:unix, _} -> "\n" | ||||
|       {:win32, _} -> "\r\n" | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -287,18 +310,22 @@ defmodule RabbitMQ.CLI.Core.Helpers do | |||
| 
 | ||||
|   def string_or_inspect(val) do | ||||
|     case String.Chars.impl_for(val) do | ||||
|       nil -> inspect(val); | ||||
|       _   -> | ||||
|         try do to_string(val) | ||||
|         catch _, _ -> inspect(val) | ||||
|       nil -> | ||||
|         inspect(val) | ||||
| 
 | ||||
|       _ -> | ||||
|         try do | ||||
|           to_string(val) | ||||
|         catch | ||||
|           _, _ -> inspect(val) | ||||
|         end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def evaluate_input_as_term(input) do | ||||
|       {:ok,tokens,_end_line} = :erl_scan.string(to_charlist(input <> ".")) | ||||
|       {:ok,abs_form} = :erl_parse.parse_exprs(tokens) | ||||
|       {:value,term_value,_bs} = :erl_eval.exprs(abs_form, :erl_eval.new_bindings()) | ||||
|       term_value | ||||
|     {:ok, tokens, _end_line} = :erl_scan.string(to_charlist(input <> ".")) | ||||
|     {:ok, abs_form} = :erl_parse.parse_exprs(tokens) | ||||
|     {:value, term_value, _bs} = :erl_eval.exprs(abs_form, :erl_eval.new_bindings()) | ||||
|     term_value | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -24,9 +24,10 @@ defmodule RabbitMQ.CLI.Core.OsPid do | |||
| 
 | ||||
|   def wait_for_os_process_death(pid) do | ||||
|     case :rabbit_misc.is_os_process_alive(pid) do | ||||
|       true  -> | ||||
|       true -> | ||||
|         :timer.sleep(@external_process_check_interval) | ||||
|         wait_for_os_process_death(pid); | ||||
|         wait_for_os_process_death(pid) | ||||
| 
 | ||||
|       false -> | ||||
|         :ok | ||||
|     end | ||||
|  | @ -36,9 +37,12 @@ defmodule RabbitMQ.CLI.Core.OsPid do | |||
|     case {:file.read_file(pidfile_path), should_wait} do | ||||
|       {{:ok, contents}, _} -> | ||||
|         pid_regex = Regex.recompile!(@pid_regex) | ||||
| 
 | ||||
|         case Regex.named_captures(pid_regex, contents)["pid"] do | ||||
|           # e.g. the file is empty | ||||
|           nil        -> {:error, :could_not_read_pid_from_file, {:contents, contents}}; | ||||
|           nil -> | ||||
|             {:error, :could_not_read_pid_from_file, {:contents, contents}} | ||||
| 
 | ||||
|           pid_string -> | ||||
|             try do | ||||
|               {pid, _remainder} = Integer.parse(pid_string) | ||||
|  | @ -48,10 +52,12 @@ defmodule RabbitMQ.CLI.Core.OsPid do | |||
|                 {:error, {:could_not_read_pid_from_file, {:contents, contents}}} | ||||
|             end | ||||
|         end | ||||
| 
 | ||||
|       # file does not exist, wait and re-check | ||||
|       {{:error, :enoent}, true} -> | ||||
|         :timer.sleep(@external_process_check_interval) | ||||
|         read_pid_from_file(pidfile_path, should_wait); | ||||
|         read_pid_from_file(pidfile_path, should_wait) | ||||
| 
 | ||||
|       {{:error, details}, _} -> | ||||
|         {:error, :could_not_read_pid_from_file, details} | ||||
|     end | ||||
|  |  | |||
|  | @ -13,22 +13,24 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Core.Output do | ||||
| 
 | ||||
|   def format_output(:ok, _, _) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   # the command intends to produce no output | ||||
|   def format_output({:ok, nil}, _, _) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def format_output({:ok, :check_passed}, _, _) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def format_output({:ok, output}, formatter, options) do | ||||
|     {:ok, formatter.format_output(output, options)} | ||||
|   end | ||||
| 
 | ||||
|   def format_output({:stream, stream}, formatter, options) do | ||||
|     {:stream, formatter.format_stream(stream, options)} | ||||
|   end | ||||
|  | @ -44,33 +46,36 @@ defmodule RabbitMQ.CLI.Core.Output do | |||
|     printer.print_ok(printer_state) | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   # the command intends to produce no output | ||||
|   def print_output_0({:ok, nil}, _printer, _printer_state) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def print_output_0({:ok, :check_passed}, _printer, _printer_state) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def print_output_0({:ok, single_value}, printer, printer_state) do | ||||
|     printer.print_output(single_value, printer_state) | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def print_output_0({:stream, stream}, printer, printer_state) do | ||||
|     case print_output_stream(stream, printer, printer_state) do | ||||
|       :ok               -> :ok; | ||||
|       :ok -> :ok | ||||
|       {:error, _} = err -> err | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def print_output_stream(stream, printer, printer_state) do | ||||
|     Enum.reduce_while(stream, :ok, | ||||
|       fn | ||||
|       ({:error, err}, _) -> | ||||
|     Enum.reduce_while(stream, :ok, fn | ||||
|       {:error, err}, _ -> | ||||
|         {:halt, {:error, err}} | ||||
|       (val, _) -> | ||||
| 
 | ||||
|       val, _ -> | ||||
|         printer.print_output(val, printer_state) | ||||
|         {:cont, :ok} | ||||
|       end) | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -20,11 +20,10 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|   # the English language is 5. | ||||
|   @levenshtein_distance_limit 5 | ||||
| 
 | ||||
|   @spec parse([String.t]) :: {command :: :no_command | atom() | {:suggest, String.t}, | ||||
|                               command_name :: String.t, | ||||
|                               arguments :: [String.t], | ||||
|                               options :: map(), | ||||
|                               invalid :: [{String.t, String.t | nil}]} | ||||
|   @spec parse([String.t()]) :: | ||||
|           {command :: :no_command | atom() | {:suggest, String.t()}, command_name :: String.t(), | ||||
|            arguments :: [String.t()], options :: map(), | ||||
|            invalid :: [{String.t(), String.t() | nil}]} | ||||
| 
 | ||||
|   def parse(input) do | ||||
|     {parsed_args, options, invalid} = parse_global(input) | ||||
|  | @ -32,16 +31,21 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
| 
 | ||||
|     case command_module do | ||||
|       nil -> | ||||
|         {:no_command, command_name, arguments, options, invalid}; | ||||
|         {:no_command, command_name, arguments, options, invalid} | ||||
| 
 | ||||
|       {:suggest, _} = suggest -> | ||||
|         {suggest, command_name, arguments, options, invalid}; | ||||
|         {suggest, command_name, arguments, options, invalid} | ||||
| 
 | ||||
|       {:alias, alias_module, alias_content} -> | ||||
|         {[_alias_command_name | cmd_arguments], cmd_options, cmd_invalid} = | ||||
|           parse_alias(input, command_name, alias_module, alias_content, options) | ||||
|         {alias_module, command_name, cmd_arguments, cmd_options, cmd_invalid}; | ||||
| 
 | ||||
|         {alias_module, command_name, cmd_arguments, cmd_options, cmd_invalid} | ||||
| 
 | ||||
|       command_module when is_atom(command_module) -> | ||||
|         {[^command_name | cmd_arguments], cmd_options, cmd_invalid} = | ||||
|           parse_command_specific(input, command_module, options) | ||||
| 
 | ||||
|         {command_module, command_name, cmd_arguments, cmd_options, cmd_invalid} | ||||
|     end | ||||
|   end | ||||
|  | @ -53,17 +57,24 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|         ## Most of the time a command will be from rabbitmqctl application | ||||
|         ## so there is not point in scanning plugins for potential commands | ||||
|         CommandModules.load_core(options) | ||||
|         core_commands = CommandModules.module_map_core | ||||
|         command = case core_commands[cmd_name] do | ||||
|           nil -> | ||||
|             CommandModules.load(options) | ||||
|             module_map = CommandModules.module_map | ||||
|             module_map[cmd_name] || | ||||
|               command_alias(cmd_name, module_map, options) || | ||||
|               command_suggestion(cmd_name, module_map); | ||||
|           c -> c | ||||
|         end | ||||
|         core_commands = CommandModules.module_map_core() | ||||
| 
 | ||||
|         command = | ||||
|           case core_commands[cmd_name] do | ||||
|             nil -> | ||||
|               CommandModules.load(options) | ||||
|               module_map = CommandModules.module_map() | ||||
| 
 | ||||
|               module_map[cmd_name] || | ||||
|                 command_alias(cmd_name, module_map, options) || | ||||
|                 command_suggestion(cmd_name, module_map) | ||||
| 
 | ||||
|             c -> | ||||
|               c | ||||
|           end | ||||
| 
 | ||||
|         {cmd_name, command, arguments} | ||||
| 
 | ||||
|       [] -> | ||||
|         {"", nil, []} | ||||
|     end | ||||
|  | @ -71,11 +82,14 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
| 
 | ||||
|   defp command_alias(cmd_name, module_map, options) do | ||||
|     aliases = load_aliases(options) | ||||
| 
 | ||||
|     case aliases[cmd_name] do | ||||
|       nil -> nil; | ||||
|       nil -> | ||||
|         nil | ||||
| 
 | ||||
|       [alias_cmd_name | _] = alias_content -> | ||||
|         case module_map[alias_cmd_name] do | ||||
|           nil -> nil; | ||||
|           nil -> nil | ||||
|           module -> {:alias, module, alias_content} | ||||
|         end | ||||
|     end | ||||
|  | @ -83,20 +97,27 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
| 
 | ||||
|   defp load_aliases(options) do | ||||
|     aliases_file = Config.get_option(:aliases_file, options) | ||||
| 
 | ||||
|     case aliases_file && File.read(aliases_file) do | ||||
|       ## No aliases file | ||||
|       nil -> %{}; | ||||
|       nil -> | ||||
|         %{} | ||||
| 
 | ||||
|       {:ok, content} -> | ||||
|         String.split(content, "\n") | ||||
|         |>  Enum.reduce(%{}, | ||||
|               fn(str, acc) -> | ||||
|                 case String.split(str, "=", parts: 2) do | ||||
|                   [alias_name, alias_string] -> | ||||
|                     Map.put(acc, String.trim(alias_name), OptionParser.split(alias_string)) | ||||
|                   _ -> | ||||
|                     acc | ||||
|                 end | ||||
|             end); | ||||
|         |> Enum.reduce( | ||||
|           %{}, | ||||
|           fn str, acc -> | ||||
|             case String.split(str, "=", parts: 2) do | ||||
|               [alias_name, alias_string] -> | ||||
|                 Map.put(acc, String.trim(alias_name), OptionParser.split(alias_string)) | ||||
| 
 | ||||
|               _ -> | ||||
|                 acc | ||||
|             end | ||||
|           end | ||||
|         ) | ||||
| 
 | ||||
|       {:error, err} -> | ||||
|         IO.puts(:stderr, "Error reading aliases file #{aliases_file}: #{err}") | ||||
|         %{} | ||||
|  | @ -106,16 +127,20 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|   defp command_suggestion(_cmd_name, empty) when empty == %{} do | ||||
|     nil | ||||
|   end | ||||
| 
 | ||||
|   defp command_suggestion(cmd_name, module_map) do | ||||
|     suggestion = module_map | ||||
|                  |> Map.keys | ||||
|                  |> Enum.map(fn(cmd) -> | ||||
|                       {cmd, Simetric.Levenshtein.compare(cmd, cmd_name)} | ||||
|                     end) | ||||
|                  |> Enum.min_by(fn({_,distance}) -> distance end) | ||||
|     suggestion = | ||||
|       module_map | ||||
|       |> Map.keys() | ||||
|       |> Enum.map(fn cmd -> | ||||
|         {cmd, Simetric.Levenshtein.compare(cmd, cmd_name)} | ||||
|       end) | ||||
|       |> Enum.min_by(fn {_, distance} -> distance end) | ||||
| 
 | ||||
|     case suggestion do | ||||
|       {cmd, distance} when distance <= @levenshtein_distance_limit -> | ||||
|         {:suggest, cmd}; | ||||
|         {:suggest, cmd} | ||||
| 
 | ||||
|       _ -> | ||||
|         nil | ||||
|     end | ||||
|  | @ -141,6 +166,7 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|   def parse_global_head(input) do | ||||
|     switches = default_switches() | ||||
|     aliases = default_aliases() | ||||
| 
 | ||||
|     {options, tail, invalid} = | ||||
|       OptionParser.parse_head( | ||||
|         input, | ||||
|  | @ -148,7 +174,8 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|         aliases: aliases, | ||||
|         allow_nonexistent_atoms: true | ||||
|       ) | ||||
|     norm_options = normalize_options(options, switches) |> Map.new | ||||
| 
 | ||||
|     norm_options = normalize_options(options, switches) |> Map.new() | ||||
|     {norm_options, tail, invalid} | ||||
|   end | ||||
| 
 | ||||
|  | @ -159,74 +186,85 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|   end | ||||
| 
 | ||||
|   defp parse_generic(input, switches, aliases) do | ||||
|     {options, args, invalid} = OptionParser.parse( | ||||
|       input, | ||||
|       strict: switches, | ||||
|       aliases: aliases, | ||||
|       allow_nonexistent_atoms: true | ||||
|     ) | ||||
|     norm_options = normalize_options(options, switches) |> Map.new | ||||
|     {options, args, invalid} = | ||||
|       OptionParser.parse( | ||||
|         input, | ||||
|         strict: switches, | ||||
|         aliases: aliases, | ||||
|         allow_nonexistent_atoms: true | ||||
|       ) | ||||
| 
 | ||||
|     norm_options = normalize_options(options, switches) |> Map.new() | ||||
|     {args, norm_options, invalid} | ||||
|   end | ||||
| 
 | ||||
|   def default_switches() do | ||||
|     [node: :atom, | ||||
|      quiet: :boolean, | ||||
|      silent: :boolean, | ||||
|      dry_run: :boolean, | ||||
|      vhost: :string, | ||||
|      # for backwards compatibility, | ||||
|      # not all commands support timeouts | ||||
|      timeout: :integer, | ||||
|      longnames: :boolean, | ||||
|      formatter: :string, | ||||
|      printer: :string, | ||||
|      file: :string, | ||||
|      script_name: :atom, | ||||
|      rabbitmq_home: :string, | ||||
|      mnesia_dir: :string, | ||||
|      plugins_dir: :string, | ||||
|      enabled_plugins_file: :string, | ||||
|      aliases_file: :string, | ||||
|      erlang_cookie: :atom | ||||
|     [ | ||||
|       node: :atom, | ||||
|       quiet: :boolean, | ||||
|       silent: :boolean, | ||||
|       dry_run: :boolean, | ||||
|       vhost: :string, | ||||
|       # for backwards compatibility, | ||||
|       # not all commands support timeouts | ||||
|       timeout: :integer, | ||||
|       longnames: :boolean, | ||||
|       formatter: :string, | ||||
|       printer: :string, | ||||
|       file: :string, | ||||
|       script_name: :atom, | ||||
|       rabbitmq_home: :string, | ||||
|       mnesia_dir: :string, | ||||
|       plugins_dir: :string, | ||||
|       enabled_plugins_file: :string, | ||||
|       aliases_file: :string, | ||||
|       erlang_cookie: :atom | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|   def default_aliases() do | ||||
|     [p: :vhost, | ||||
|      n: :node, | ||||
|      q: :quiet, | ||||
|      s: :silent, | ||||
|      l: :longnames, | ||||
|      # for backwards compatibility, | ||||
|      # not all commands support timeouts | ||||
|      t: :timeout] | ||||
|     [ | ||||
|       p: :vhost, | ||||
|       n: :node, | ||||
|       q: :quiet, | ||||
|       s: :silent, | ||||
|       l: :longnames, | ||||
|       # for backwards compatibility, | ||||
|       # not all commands support timeouts | ||||
|       t: :timeout | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|   defp build_switches(default, command, formatter) do | ||||
|     command_switches = apply_if_exported(command, :switches, [], []) | ||||
|     formatter_switches = apply_if_exported(formatter, :switches, [], []) | ||||
| 
 | ||||
|     assert_no_conflict(command, command_switches, formatter_switches, | ||||
|                        :redefining_formatter_switches) | ||||
| 
 | ||||
|     merge_if_different(default, formatter_switches, | ||||
|                        {:formatter_invalid, | ||||
|                         {formatter, {:redefining_global_switches, | ||||
|                                      default, | ||||
|                                      formatter_switches}}}) | ||||
|     |> merge_if_different(command_switches, | ||||
|                           {:command_invalid, | ||||
|                            {command, {:redefining_global_switches, | ||||
|                                       default, | ||||
|                                       command_switches}}}) | ||||
|     assert_no_conflict( | ||||
|       command, | ||||
|       command_switches, | ||||
|       formatter_switches, | ||||
|       :redefining_formatter_switches | ||||
|     ) | ||||
| 
 | ||||
|     merge_if_different( | ||||
|       default, | ||||
|       formatter_switches, | ||||
|       {:formatter_invalid, | ||||
|        {formatter, {:redefining_global_switches, default, formatter_switches}}} | ||||
|     ) | ||||
|     |> merge_if_different( | ||||
|       command_switches, | ||||
|       {:command_invalid, {command, {:redefining_global_switches, default, command_switches}}} | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   defp assert_no_conflict(command, command_fields, formatter_fields, err) do | ||||
|     merge_if_different(formatter_fields, command_fields, | ||||
|                        {:command_invalid, | ||||
|                         {command, {err, formatter_fields, command_fields}}}) | ||||
|     merge_if_different( | ||||
|       formatter_fields, | ||||
|       command_fields, | ||||
|       {:command_invalid, {command, {err, formatter_fields, command_fields}}} | ||||
|     ) | ||||
| 
 | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|  | @ -234,40 +272,43 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|     command_aliases = apply_if_exported(command, :aliases, [], []) | ||||
|     formatter_aliases = apply_if_exported(formatter, :aliases, [], []) | ||||
| 
 | ||||
|     assert_no_conflict(command, command_aliases, formatter_aliases, | ||||
|                        :redefining_formatter_aliases) | ||||
|     assert_no_conflict(command, command_aliases, formatter_aliases, :redefining_formatter_aliases) | ||||
| 
 | ||||
|     merge_if_different(default, formatter_aliases, | ||||
|                        {:formatter_invalid, | ||||
|                         {command, {:redefining_global_aliases, | ||||
|                                    default, | ||||
|                                    formatter_aliases}}}) | ||||
|     |> merge_if_different(command_aliases, | ||||
|                           {:command_invalid, | ||||
|                            {command, {:redefining_global_aliases, | ||||
|                                       default, | ||||
|                                       command_aliases}}}) | ||||
|     merge_if_different( | ||||
|       default, | ||||
|       formatter_aliases, | ||||
|       {:formatter_invalid, {command, {:redefining_global_aliases, default, formatter_aliases}}} | ||||
|     ) | ||||
|     |> merge_if_different( | ||||
|       command_aliases, | ||||
|       {:command_invalid, {command, {:redefining_global_aliases, default, command_aliases}}} | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   defp apply_if_exported(mod, fun, args, default) do | ||||
|     Code.ensure_loaded(mod) | ||||
| 
 | ||||
|     case function_exported?(mod, fun, length(args)) do | ||||
|       true  -> apply(mod, fun, args); | ||||
|       true -> apply(mod, fun, args) | ||||
|       false -> default | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   defp merge_if_different(default, specific, error) do | ||||
|     case keyword_intersect(default, specific) do | ||||
|       []        -> Keyword.merge(default, specific); | ||||
|       [] -> | ||||
|         Keyword.merge(default, specific) | ||||
| 
 | ||||
|       conflicts -> | ||||
|         # if all conflicting keys are of the same type, | ||||
|         # that's acceptable | ||||
|         case Enum.all?(conflicts, | ||||
|               fn(c) -> | ||||
|                 Keyword.get(default, c) == Keyword.get(specific, c) | ||||
|               end) do | ||||
|           true  -> Keyword.merge(default, specific); | ||||
|         case Enum.all?( | ||||
|                conflicts, | ||||
|                fn c -> | ||||
|                  Keyword.get(default, c) == Keyword.get(specific, c) | ||||
|                end | ||||
|              ) do | ||||
|           true -> Keyword.merge(default, specific) | ||||
|           false -> exit(error) | ||||
|         end | ||||
|     end | ||||
|  | @ -277,24 +318,27 @@ defmodule RabbitMQ.CLI.Core.Parser do | |||
|     one_keys = MapSet.new(Keyword.keys(one)) | ||||
|     two_keys = MapSet.new(Keyword.keys(two)) | ||||
|     intersection = MapSet.intersection(one_keys, two_keys) | ||||
| 
 | ||||
|     case Enum.empty?(intersection) do | ||||
|       true  -> []; | ||||
|       true -> [] | ||||
|       false -> MapSet.to_list(intersection) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   defp normalize_options(options, switches) do | ||||
|     Enum.map(options, | ||||
|              fn({key, option}) -> | ||||
|                {key, normalize_type(option, switches[key])} | ||||
|              end) | ||||
|     Enum.map( | ||||
|       options, | ||||
|       fn {key, option} -> | ||||
|         {key, normalize_type(option, switches[key])} | ||||
|       end | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   defp normalize_type(value, :atom) when is_binary(value) do | ||||
|     String.to_atom(value) | ||||
|   end | ||||
| 
 | ||||
|   defp normalize_type(value, _type) do | ||||
|     value | ||||
|   end | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -19,73 +19,74 @@ defmodule RabbitMQ.CLI.Core.Validators do | |||
| 
 | ||||
|   def chain([validator | rest], args) do | ||||
|     case apply(validator, args) do | ||||
|       :ok                        -> chain(rest, args) | ||||
|       {:ok, _}                   -> chain(rest, args) | ||||
|       :ok -> chain(rest, args) | ||||
|       {:ok, _} -> chain(rest, args) | ||||
|       {:validation_failure, err} -> {:validation_failure, err} | ||||
|       {:error, err}              -> {:validation_failure, err} | ||||
|       {:error, err} -> {:validation_failure, err} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def chain([], _) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def node_is_not_running(_, %{node: node_name}) do | ||||
|     case Helpers.node_running?(node_name) do | ||||
|       true  -> {:validation_failure, :node_running}; | ||||
|       true -> {:validation_failure, :node_running} | ||||
|       false -> :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def node_is_running(_, %{node: node_name}) do | ||||
|     case Helpers.node_running?(node_name) do | ||||
|       false -> {:validation_failure, :node_not_running}; | ||||
|       true  -> :ok | ||||
|       false -> {:validation_failure, :node_not_running} | ||||
|       true -> :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def mnesia_dir_is_set(_, opts) do | ||||
|     case Helpers.require_mnesia_dir(opts) do | ||||
|       :ok           -> :ok; | ||||
|       :ok -> :ok | ||||
|       {:error, err} -> {:validation_failure, err} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def rabbit_is_loaded(_, opts) do | ||||
|     case Helpers.require_rabbit(opts) do | ||||
|       :ok           -> :ok; | ||||
|       :ok -> :ok | ||||
|       {:error, err} -> {:validation_failure, err} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def rabbit_is_running(args, opts) do | ||||
|     case rabbit_app_state(args, opts) do | ||||
|       :running -> :ok; | ||||
|       :stopped -> {:validation_failure, :rabbit_app_is_stopped}; | ||||
|       other    -> other | ||||
|       :running -> :ok | ||||
|       :stopped -> {:validation_failure, :rabbit_app_is_stopped} | ||||
|       other -> other | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def rabbit_is_running_or_offline_flag_used(_args, %{offline: true}) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def rabbit_is_running_or_offline_flag_used(args, opts) do | ||||
|     rabbit_is_running(args, opts) | ||||
|   end | ||||
| 
 | ||||
|   def rabbit_is_not_running(args, opts) do | ||||
|     case rabbit_app_state(args, opts) do | ||||
|       :running -> {:validation_failure, :rabbit_app_is_running}; | ||||
|       :stopped -> :ok; | ||||
|       other    -> other | ||||
|       :running -> {:validation_failure, :rabbit_app_is_running} | ||||
|       :stopped -> :ok | ||||
|       other -> other | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def rabbit_app_state(_, opts) do | ||||
|     case Helpers.rabbit_app_running?(opts) do | ||||
|       true          -> :running; | ||||
|       false         -> :stopped; | ||||
|       true -> :running | ||||
|       false -> :stopped | ||||
|       {:error, err} -> {:error, err} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,9 +13,7 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.AddUserCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.{ExitCodes, Helpers} | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|  | @ -34,14 +32,17 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AddUserCommand do | |||
|     {:validation_failure, {:bad_argument, "user cannot be empty string."}} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_,_], _), do: :ok | ||||
|   def validate([_, _], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_, _] = args, %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :add_user, args ++ [Helpers.cli_acting_user()]) | ||||
|       :add_user, | ||||
|       args ++ [Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "add_user <username> <password>" | ||||
|  | @ -51,5 +52,6 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AddUserCommand do | |||
|   def output({:error, {:user_already_exists, username}}, _) do | ||||
|     {:error, ExitCodes.exit_software(), "User \"#{username}\" already exists"} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -13,9 +13,7 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.AddVhostCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|  | @ -24,7 +22,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AddVhostCommand do | |||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.AuthenticateUserCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
| 
 | ||||
|  | @ -21,12 +20,13 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AuthenticateUserCommand do | |||
| 
 | ||||
|   def validate(args, _) when length(args) < 2, do: {:validation_failure, :not_enough_args} | ||||
|   def validate(args, _) when length(args) > 2, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_,_], _), do: :ok | ||||
|   def validate([_, _], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([user, password], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_access_control, | ||||
|       :check_user_pass_login, | ||||
|       [user, password] | ||||
|  | @ -38,12 +38,14 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AuthenticateUserCommand do | |||
|   def banner([username, _password], _), do: "Authenticating user \"#{username}\" ..." | ||||
| 
 | ||||
|   def output({:refused, user, msg, args}, _) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_dataerr, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_dataerr(), | ||||
|      "Error: failed to authenticate user \"#{user}\"\n" <> | ||||
|      to_string(:io_lib.format(msg, args))} | ||||
|        to_string(:io_lib.format(msg, args))} | ||||
|   end | ||||
| 
 | ||||
|   def output({:ok, _user}, _) do | ||||
|     {:ok, "Success"} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -13,18 +13,19 @@ | |||
| ## The Initial Developer of the Original Code is Pivotal Software, Inc. | ||||
| ## Copyright (c) 2016-2018 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.AwaitOnlineNodesCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
| 
 | ||||
|   @default_timeout 300_000 | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     timeout = case opts[:timeout] do | ||||
|       nil       -> @default_timeout; | ||||
|       :infinity -> @default_timeout; | ||||
|       other     -> other | ||||
|     end | ||||
|     timeout = | ||||
|       case opts[:timeout] do | ||||
|         nil -> @default_timeout | ||||
|         :infinity -> @default_timeout | ||||
|         other -> other | ||||
|       end | ||||
| 
 | ||||
|     {args, Map.merge(opts, %{timeout: timeout})} | ||||
|   end | ||||
| 
 | ||||
|  | @ -34,8 +35,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AwaitOnlineNodesCommand do | |||
| 
 | ||||
|   def run([count], %{node: node_name, timeout: timeout}) do | ||||
|     {n, _} = Integer.parse(count) | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_nodes, :await_running_count, [n, timeout]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_nodes, :await_running_count, [n, timeout]) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|  | @ -43,15 +43,19 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AwaitOnlineNodesCommand do | |||
|   end | ||||
| 
 | ||||
|   def banner([count], %{node: node_name, timeout: timeout}) when is_number(timeout) do | ||||
|     "Will wait for at least #{count} nodes to join the cluster of #{node_name}. Timeout: #{trunc(timeout / 1000)} seconds." | ||||
|     "Will wait for at least #{count} nodes to join the cluster of #{node_name}. Timeout: #{ | ||||
|       trunc(timeout / 1000) | ||||
|     } seconds." | ||||
|   end | ||||
| 
 | ||||
|   def banner([count], %{node: node_name, timeout: _timeout}) do | ||||
|     "Will wait for at least #{count} nodes to join the cluster of #{node_name}." | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :timeout}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      "Error: timed out while waiting. Not enough nodes joined #{node_name}'s cluster."} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -35,9 +35,13 @@ defmodule RabbitMQ.CLI.Ctl.Commands.AwaitStartupCommand do | |||
|   use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments | ||||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout} = opts) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit, :await_startup, | ||||
|                           [node_name, not output_less?(opts), timeout]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit, :await_startup, [ | ||||
|       node_name, | ||||
|       not output_less?(opts), | ||||
|       timeout | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def usage, do: "await_startup" | ||||
|  |  | |||
|  | @ -23,14 +23,15 @@ defmodule RabbitMQ.CLI.Ctl.Commands.CancelSyncQueueCommand do | |||
| 
 | ||||
|   def usage, do: "cancel_sync_queue [-p <vhost>] queue" | ||||
| 
 | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_], _), do: :ok | ||||
|   def validate(_, _),   do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([queue], %{vhost: vhost, node: node_name}) do | ||||
|     :rpc.call(node_name, | ||||
|     :rpc.call( | ||||
|       node_name, | ||||
|       :rabbit_mirror_queue_misc, | ||||
|       :cancel_sync_queue, | ||||
|       [:rabbit_misc.r(vhost, :queue, queue)], | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is Pivotal Software, Inc. | ||||
| ## Copyright (c) 2016-2017 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ChangeClusterNodeTypeCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
| 
 | ||||
|  | @ -21,27 +20,32 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ChangeClusterNodeTypeCommand do | |||
|     {args, opts} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
| 
 | ||||
|   # node type | ||||
|   def validate(["disc"], _), do: :ok | ||||
|   def validate(["disk"], _), do: :ok | ||||
|   def validate(["ram"], _),  do: :ok | ||||
|   def validate(["ram"], _), do: :ok | ||||
| 
 | ||||
|   def validate([_], _), do: {:validation_failure, {:bad_argument, "The node type must be either disc or ram."}} | ||||
|   def validate(_, _),   do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], _), | ||||
|     do: {:validation_failure, {:bad_argument, "The node type must be either disc or ram."}} | ||||
| 
 | ||||
|   def validate(_, _), do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppStopped | ||||
| 
 | ||||
|   def run([node_type_arg], %{node: node_name}) do | ||||
|     normalized_type = normalize_type(String.to_atom(node_type_arg)) | ||||
|     current_type = :rabbit_misc.rpc_call(node_name, | ||||
|                                          :rabbit_mnesia, :node_type, []) | ||||
|     current_type = :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :node_type, []) | ||||
| 
 | ||||
|     case current_type do | ||||
|       ^normalized_type -> {:ok, "Node type is already #{normalized_type}"}; | ||||
|       ^normalized_type -> | ||||
|         {:ok, "Node type is already #{normalized_type}"} | ||||
| 
 | ||||
|       _ -> | ||||
|         :rabbit_misc.rpc_call(node_name, | ||||
|                               :rabbit_mnesia, :change_cluster_node_type, [normalized_type]) | ||||
|         :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :change_cluster_node_type, [ | ||||
|           normalized_type | ||||
|         ]) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -54,17 +58,20 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ChangeClusterNodeTypeCommand do | |||
|   end | ||||
| 
 | ||||
|   def output({:error, :mnesia_unexpectedly_running}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      RabbitMQ.CLI.DefaultOutput.mnesia_running_error(node_name)} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   defp normalize_type(:ram) do | ||||
|     :ram | ||||
|   end | ||||
| 
 | ||||
|   defp normalize_type(:disc) do | ||||
|     :disc | ||||
|   end | ||||
| 
 | ||||
|   defp normalize_type(:disk) do | ||||
|     :disc | ||||
|   end | ||||
|  |  | |||
|  | @ -13,9 +13,7 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ChangePasswordCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|  | @ -23,18 +21,21 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ChangePasswordCommand do | |||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate(args, _) when length(args) < 2, do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_|_] = args, _) when length(args) > 2, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 2, do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_user, _] = args, %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_auth_backend_internal, :change_password, args ++ [Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :change_password, | ||||
|       args ++ [Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "change_password <username> <password>" | ||||
| 
 | ||||
|   def banner([user| _], _), do: "Changing password for user \"#{user}\" ..." | ||||
| 
 | ||||
|   def banner([user | _], _), do: "Changing password for user \"#{user}\" ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,13 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearGlobalParameterCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, opts} | ||||
|   end | ||||
|  | @ -27,18 +26,22 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearGlobalParameterCommand do | |||
|   def validate(args, _) when is_list(args) and length(args) < 1 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_|_] = args, _) when length(args) > 1 do | ||||
| 
 | ||||
|   def validate([_ | _] = args, _) when length(args) > 1 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([key], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_runtime_parameters, | ||||
|       :clear_global, | ||||
|       [key, Helpers.cli_acting_user()]) | ||||
|       [key, Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "clear_global_parameter <key>" | ||||
|  |  | |||
|  | @ -13,13 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearOperatorPolicyCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{vhost: "/"}, opts)} | ||||
|   end | ||||
|  | @ -27,21 +26,25 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearOperatorPolicyCommand do | |||
|   def validate([], _) do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_,_|_], _) do | ||||
| 
 | ||||
|   def validate([_, _ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([key], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_policy, :delete_op, [vhost, key, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_policy, :delete_op, [ | ||||
|       vhost, | ||||
|       key, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "clear_operator_policy [-p <vhost>] <key>" | ||||
| 
 | ||||
| 
 | ||||
|   def banner([key], %{vhost: vhost}) do | ||||
|     "Clearing operator policy \"#{key}\" on vhost \"#{vhost}\" ..." | ||||
|   end | ||||
|  |  | |||
|  | @ -13,13 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearParameterCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{vhost: "/"}, opts)} | ||||
|   end | ||||
|  | @ -27,23 +26,26 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearParameterCommand do | |||
|   def validate(args, _) when is_list(args) and length(args) < 2 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_|_] = args, _) when length(args) > 2 do | ||||
| 
 | ||||
|   def validate([_ | _] = args, _) when length(args) > 2 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
|   def validate([_,_], _), do: :ok | ||||
| 
 | ||||
|   def validate([_, _], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([component_name, key], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_runtime_parameters, | ||||
|       :clear, | ||||
|       [vhost, component_name, key, Helpers.cli_acting_user()]) | ||||
|       [vhost, component_name, key, Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "clear_parameter [-p <vhost>] <component_name> <key>" | ||||
| 
 | ||||
| 
 | ||||
|   def banner([component_name, key], %{vhost: vhost}) do | ||||
|     "Clearing runtime parameter \"#{key}\" for component \"#{component_name}\" on vhost \"#{vhost}\" ..." | ||||
|   end | ||||
|  |  | |||
|  | @ -13,9 +13,7 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearPasswordCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|  | @ -24,18 +22,21 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearPasswordCommand do | |||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_user] = args, %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_auth_backend_internal, :clear_password, | ||||
|       args ++ [Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :clear_password, | ||||
|       args ++ [Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "clear_password <username>" | ||||
| 
 | ||||
|   def banner([user], _), do: "Clearing password for user \"#{user}\" ..." | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearPermissionsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -28,18 +27,23 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearPermissionsCommand do | |||
|   def validate([], _) do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_|_] = args, _) when length(args) > 1 do | ||||
| 
 | ||||
|   def validate([_ | _] = args, _) when length(args) > 1 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   def run([username], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_auth_backend_internal, :clear_permissions, [username, vhost, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_auth_backend_internal, :clear_permissions, [ | ||||
|       username, | ||||
|       vhost, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "clear_permissions [-p vhost] <username>" | ||||
| 
 | ||||
|   def banner([username], %{vhost: vhost}), do: "Clearing permissions for user \"#{username}\" in vhost \"#{vhost}\" ..." | ||||
| 
 | ||||
|   def banner([username], %{vhost: vhost}), | ||||
|     do: "Clearing permissions for user \"#{username}\" in vhost \"#{vhost}\" ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,12 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearPolicyCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{vhost: "/"}, opts)} | ||||
|   end | ||||
|  | @ -26,21 +26,25 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearPolicyCommand do | |||
|   def validate([], _) do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_,_|_], _) do | ||||
| 
 | ||||
|   def validate([_, _ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([key], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_policy, :delete, [vhost, key, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_policy, :delete, [ | ||||
|       vhost, | ||||
|       key, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "clear_policy [-p <vhost>] <key>" | ||||
| 
 | ||||
| 
 | ||||
|   def banner([key], %{vhost: vhost}) do | ||||
|     "Clearing policy \"#{key}\" on vhost \"#{vhost}\" ..." | ||||
|   end | ||||
|  |  | |||
|  | @ -13,13 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearTopicPermissionsCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{vhost: "/"}, opts)} | ||||
|   end | ||||
|  | @ -27,25 +26,39 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearTopicPermissionsCommand do | |||
|   def validate([], _) do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_|_] = args, _) when length(args) > 2 do | ||||
| 
 | ||||
|   def validate([_ | _] = args, _) when length(args) > 2 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_], _), do: :ok | ||||
|   def validate([_, _], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([username], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_auth_backend_internal, :clear_topic_permissions, [username, vhost, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_auth_backend_internal, :clear_topic_permissions, [ | ||||
|       username, | ||||
|       vhost, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def run([username, exchange], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_auth_backend_internal, :clear_topic_permissions, [username, vhost, exchange, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_auth_backend_internal, :clear_topic_permissions, [ | ||||
|       username, | ||||
|       vhost, | ||||
|       exchange, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "clear_topic_permissions [-p vhost] <username> [<exchange>]" | ||||
| 
 | ||||
|   def banner([username], %{vhost: vhost}), do: "Clearing topic permissions for user \"#{username}\" in vhost \"#{vhost}\" ..." | ||||
|   def banner([username, exchange], %{vhost: vhost}), do: "Clearing topic permissions on \"#{exchange}\" for user \"#{username}\" in vhost \"#{vhost}\" ..." | ||||
|   def banner([username], %{vhost: vhost}), | ||||
|     do: "Clearing topic permissions for user \"#{username}\" in vhost \"#{vhost}\" ..." | ||||
| 
 | ||||
|   def banner([username, exchange], %{vhost: vhost}), | ||||
|     do: | ||||
|       "Clearing topic permissions on \"#{exchange}\" for user \"#{username}\" in vhost \"#{vhost}\" ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClearVhostLimitsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -32,12 +31,15 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClearVhostLimitsCommand do | |||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 1 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 1 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def run([], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_vhost_limit, :clear, [vhost, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_vhost_limit, :clear, [ | ||||
|       vhost, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.CloseAllConnectionsCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   def merge_defaults(args, opts) do | ||||
|  | @ -26,22 +25,37 @@ defmodule RabbitMQ.CLI.Ctl.Commands.CloseAllConnectionsCommand do | |||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([explanation], %{node: node_name, vhost: vhost, global: global_opt, | ||||
|                            per_connection_delay: delay, limit: limit}) do | ||||
|     conns = case global_opt do | ||||
|               false -> | ||||
|                 per_vhost = :rabbit_misc.rpc_call(node_name, :rabbit_connection_tracking, :list, [vhost]) | ||||
|                 apply_limit(per_vhost, limit) | ||||
|               true -> | ||||
|                 :rabbit_misc.rpc_call(node_name, :rabbit_connection_tracking, | ||||
|                   :list_on_node, [node_name]) | ||||
|             end | ||||
|   def run([explanation], %{ | ||||
|         node: node_name, | ||||
|         vhost: vhost, | ||||
|         global: global_opt, | ||||
|         per_connection_delay: delay, | ||||
|         limit: limit | ||||
|       }) do | ||||
|     conns = | ||||
|       case global_opt do | ||||
|         false -> | ||||
|           per_vhost = | ||||
|             :rabbit_misc.rpc_call(node_name, :rabbit_connection_tracking, :list, [vhost]) | ||||
| 
 | ||||
|           apply_limit(per_vhost, limit) | ||||
| 
 | ||||
|         true -> | ||||
|           :rabbit_misc.rpc_call(node_name, :rabbit_connection_tracking, :list_on_node, [node_name]) | ||||
|       end | ||||
| 
 | ||||
|     case conns do | ||||
|       {:badrpc, _} = err -> | ||||
|         err | ||||
| 
 | ||||
|       _ -> | ||||
|         :rabbit_misc.rpc_call(node_name, :rabbit_connection_tracking_handler, | ||||
|           :close_connections, [conns, explanation, delay]) | ||||
|         :rabbit_misc.rpc_call( | ||||
|           node_name, | ||||
|           :rabbit_connection_tracking_handler, | ||||
|           :close_connections, | ||||
|           [conns, explanation, delay] | ||||
|         ) | ||||
| 
 | ||||
|         {:ok, "Closed #{length(conns)} connections"} | ||||
|     end | ||||
|   end | ||||
|  | @ -49,25 +63,31 @@ defmodule RabbitMQ.CLI.Ctl.Commands.CloseAllConnectionsCommand do | |||
|   defp apply_limit(conns, 0) do | ||||
|     conns | ||||
|   end | ||||
| 
 | ||||
|   defp apply_limit(conns, number) do | ||||
|     :lists.sublist(conns, number) | ||||
|   end | ||||
| 
 | ||||
|   def output({:stream, stream}, _opts) do | ||||
|     {:stream, Stream.filter(stream, fn(x) -> x != :ok end)} | ||||
|     {:stream, Stream.filter(stream, fn x -> x != :ok end)} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def switches(), do: [global: :boolean, per_connection_delay: :integer, limit: :integer] | ||||
| 
 | ||||
|   def usage, do: "close_all_connections [-p <vhost> --limit <limit>] [-n <node> --global] [--per-connection-delay <delay>] <explanation>" | ||||
|   def usage, | ||||
|     do: | ||||
|       "close_all_connections [-p <vhost> --limit <limit>] [-n <node> --global] [--per-connection-delay <delay>] <explanation>" | ||||
| 
 | ||||
|   def banner([explanation], %{node: node_name, global: true}) do | ||||
|     "Closing all connections to node #{node_name} (across all vhosts), reason: #{explanation}..." | ||||
|   end | ||||
| 
 | ||||
|   def banner([explanation], %{vhost: vhost, limit: 0}) do | ||||
|     "Closing all connections in vhost #{vhost}, reason: #{explanation}..." | ||||
|   end | ||||
| 
 | ||||
|   def banner([explanation], %{vhost: vhost, limit: limit}) do | ||||
|     "Closing #{limit} connections in vhost #{vhost}, reason: #{explanation}..." | ||||
|   end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.CloseConnectionCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -21,14 +20,15 @@ defmodule RabbitMQ.CLI.Ctl.Commands.CloseConnectionCommand do | |||
| 
 | ||||
|   def validate(args, _) when length(args) > 2, do: {:validation_failure, :too_many_args} | ||||
|   def validate(args, _) when length(args) < 2, do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_,_], _), do: :ok | ||||
|   def validate([_, _], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
|    | ||||
| 
 | ||||
|   def run([pid, explanation], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_networking, | ||||
|       :close_connection, | ||||
|       [:rabbit_misc.string_to_pid(pid), explanation]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_networking, :close_connection, [ | ||||
|       :rabbit_misc.string_to_pid(pid), | ||||
|       explanation | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "close_connection <connectionpid> <explanation>" | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ClusterStatusCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -29,12 +28,15 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ClusterStatusCommand do | |||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :status, []) do | ||||
|       {:badrpc, _} = err -> | ||||
|         err | ||||
| 
 | ||||
|       status -> | ||||
|         case :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :cluster_nodes, [:running]) do | ||||
|           {:badrpc, _} = err -> | ||||
|             err | ||||
| 
 | ||||
|           {:error, {:corrupt_or_missing_cluster_files, _, _}} -> | ||||
|             {:error, "Could not read mnesia files containing cluster status"} | ||||
| 
 | ||||
|           nodes -> | ||||
|             alarms_by_node = Enum.map(nodes, &alarms_by_node/1) | ||||
|             status ++ [{:alarms, alarms_by_node}] | ||||
|  |  | |||
|  | @ -20,56 +20,76 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do | |||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def switches() do | ||||
|       [ | ||||
|         cipher: :atom, | ||||
|         hash: :atom, | ||||
|         iterations: :integer | ||||
|       ] | ||||
|     [ | ||||
|       cipher: :atom, | ||||
|       hash: :atom, | ||||
|       iterations: :integer | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|   def distribution(_), do: :none | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{ | ||||
|         cipher:       :rabbit_pbe.default_cipher(), | ||||
|         hash:         :rabbit_pbe.default_hash(), | ||||
|         iterations:   :rabbit_pbe.default_iterations() | ||||
|         }, opts) | ||||
|     } | ||||
|     {args, | ||||
|      Map.merge( | ||||
|        %{ | ||||
|          cipher: :rabbit_pbe.default_cipher(), | ||||
|          hash: :rabbit_pbe.default_hash(), | ||||
|          iterations: :rabbit_pbe.default_iterations() | ||||
|        }, | ||||
|        opts | ||||
|      )} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) when length(args) < 2 do | ||||
|       {:validation_failure, | ||||
|        {:bad_argument, "Please provide a value to decode and a passphrase."}} | ||||
|     {:validation_failure, {:bad_argument, "Please provide a value to decode and a passphrase."}} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) when length(args) > 2 do | ||||
|       {:validation_failure, :too_many_args} | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, opts) when length(args) === 2 do | ||||
|     case {supports_cipher(opts.cipher), supports_hash(opts.hash), opts.iterations > 0} do | ||||
|       {false, _, _}      -> {:validation_failure, {:bad_argument, "The requested cipher is not supported."}} | ||||
|       {_, false, _}      -> {:validation_failure, {:bad_argument, "The requested hash is not supported"}} | ||||
|       {_, _, false}      -> {:validation_failure, {:bad_argument, "The requested number of iterations is incorrect (must be a positive integer)"}} | ||||
|       {true, true, true} -> :ok | ||||
|       {false, _, _} -> | ||||
|         {:validation_failure, {:bad_argument, "The requested cipher is not supported."}} | ||||
| 
 | ||||
|       {_, false, _} -> | ||||
|         {:validation_failure, {:bad_argument, "The requested hash is not supported"}} | ||||
| 
 | ||||
|       {_, _, false} -> | ||||
|         {:validation_failure, | ||||
|          {:bad_argument, | ||||
|           "The requested number of iterations is incorrect (must be a positive integer)"}} | ||||
| 
 | ||||
|       {true, true, true} -> | ||||
|         :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def run([value, passphrase], %{cipher: cipher, hash: hash, iterations: iterations}) do | ||||
|     try do | ||||
|       term_value = Helpers.evaluate_input_as_term(value) | ||||
|       term_to_decrypt = case term_value do | ||||
|         {:encrypted, encrypted_term} -> encrypted_term | ||||
|         _                            -> term_value | ||||
|       end | ||||
| 
 | ||||
|       term_to_decrypt = | ||||
|         case term_value do | ||||
|           {:encrypted, encrypted_term} -> encrypted_term | ||||
|           _ -> term_value | ||||
|         end | ||||
| 
 | ||||
|       result = :rabbit_pbe.decrypt_term(cipher, hash, iterations, passphrase, term_to_decrypt) | ||||
|       {:ok, result} | ||||
|     catch _, _ -> | ||||
|       {:error, "Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"} | ||||
|     catch | ||||
|       _, _ -> | ||||
|         {:error, | ||||
|          "Failed to decrypt the value. Things to check: is the passphrase correct? Are the cipher and hash algorithms the same as those used for encryption?"} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def formatter(), do: RabbitMQ.CLI.Formatters.Erlang | ||||
| 
 | ||||
|   def usage, do: "decode value passphrase [--cipher cipher] [--hash hash] [--iterations iterations]" | ||||
|   def usage, | ||||
|     do: "decode value passphrase [--cipher cipher] [--hash hash] [--iterations iterations]" | ||||
| 
 | ||||
|   def banner([_, _], _) do | ||||
|     "Decrypting value ..." | ||||
|  | @ -78,5 +98,4 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DecodeCommand do | |||
|   defp supports_cipher(cipher), do: Enum.member?(:rabbit_pbe.supported_ciphers(), cipher) | ||||
| 
 | ||||
|   defp supports_hash(hash), do: Enum.member?(:rabbit_pbe.supported_hashes(), hash) | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.DeleteQueueCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
| 
 | ||||
|  | @ -22,17 +21,19 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DeleteQueueCommand do | |||
| 
 | ||||
|   def usage(), do: "delete_queue queue_name [--if_empty|-e] [--if_unused|-u]" | ||||
| 
 | ||||
|   def banner([qname], %{vhost: vhost, | ||||
|                         if_empty: if_empty, | ||||
|                         if_unused: if_unused}) do | ||||
|     if_empty_str = case if_empty do | ||||
|       true  -> ["if queue is empty "] | ||||
|       false -> [] | ||||
|     end | ||||
|     if_unused_str = case if_unused do | ||||
|       true  -> ["if queue is unused "] | ||||
|       false -> [] | ||||
|     end | ||||
|   def banner([qname], %{vhost: vhost, if_empty: if_empty, if_unused: if_unused}) do | ||||
|     if_empty_str = | ||||
|       case if_empty do | ||||
|         true -> ["if queue is empty "] | ||||
|         false -> [] | ||||
|       end | ||||
| 
 | ||||
|     if_unused_str = | ||||
|       case if_unused do | ||||
|         true -> ["if queue is unused "] | ||||
|         false -> [] | ||||
|       end | ||||
| 
 | ||||
|     "Deleting queue '#{qname}' on vhost '#{vhost}' " <> | ||||
|       Enum.join(Enum.concat([if_empty_str, if_unused_str]), "and ") <> "..." | ||||
|   end | ||||
|  | @ -50,48 +51,64 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DeleteQueueCommand do | |||
|   def validate([], _options) do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_,_|_], _options) do | ||||
| 
 | ||||
|   def validate([_, _ | _], _options) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([""], _options) do | ||||
|     { | ||||
|       :validation_failure, | ||||
|       {:bad_argument, "queue name cannot be empty string."} | ||||
|     } | ||||
|   end | ||||
| 
 | ||||
|   def validate([_], _options) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def run([qname], %{node: node, vhost: vhost, | ||||
|                      if_empty: if_empty, if_unused: if_unused, | ||||
|                      timeout: timeout}) do | ||||
|   def run([qname], %{ | ||||
|         node: node, | ||||
|         vhost: vhost, | ||||
|         if_empty: if_empty, | ||||
|         if_unused: if_unused, | ||||
|         timeout: timeout | ||||
|       }) do | ||||
|     ## Generate queue resource name from queue name and vhost | ||||
|     queue_resource = :rabbit_misc.r(vhost, :queue, qname) | ||||
|     ## Lookup a queue on broker node using resource name | ||||
|     case :rabbit_misc.rpc_call(node, :rabbit_amqqueue, :lookup, | ||||
|                                      [queue_resource]) do | ||||
|     case :rabbit_misc.rpc_call(node, :rabbit_amqqueue, :lookup, [queue_resource]) do | ||||
|       {:ok, queue} -> | ||||
|         ## Delete queue | ||||
|         :rabbit_misc.rpc_call(node, :rabbit_amqqueue, :delete, | ||||
|                                     [queue, if_unused, if_empty, "cli_user"], | ||||
|                               timeout); | ||||
|       {:error, _} = error -> error | ||||
|         :rabbit_misc.rpc_call( | ||||
|           node, | ||||
|           :rabbit_amqqueue, | ||||
|           :delete, | ||||
|           [queue, if_unused, if_empty, "cli_user"], | ||||
|           timeout | ||||
|         ) | ||||
| 
 | ||||
|       {:error, _} = error -> | ||||
|         error | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :not_found}, _options) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage, "Queue not found"} | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), "Queue not found"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :not_empty}, _options) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage, "Queue is not empty"} | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), "Queue is not empty"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :in_use}, _options) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage, "Queue is in use"} | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_usage(), "Queue is in use"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:ok, qlen}, _options) do | ||||
|     {:ok, "Queue was successfully deleted with #{qlen} messages"} | ||||
|   end | ||||
| 
 | ||||
|   ## Use default output for all non-special case outputs | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.DeleteUserCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -29,7 +28,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DeleteUserCommand do | |||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([username], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :delete_user, | ||||
|       [username, Helpers.cli_acting_user()] | ||||
|  | @ -39,5 +39,4 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DeleteUserCommand do | |||
|   def usage, do: "delete_user <username>" | ||||
| 
 | ||||
|   def banner([arg], _), do: "Deleting user \"#{arg}\" ..." | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.DeleteVhostCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -23,7 +22,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.DeleteVhostCommand do | |||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
|  |  | |||
|  | @ -30,26 +30,38 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do | |||
|   def distribution(_), do: :none | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{ | ||||
|         cipher:       :rabbit_pbe.default_cipher(), | ||||
|         hash:         :rabbit_pbe.default_hash(), | ||||
|         iterations:   :rabbit_pbe.default_iterations() | ||||
|         }, opts) | ||||
|     } | ||||
|     {args, | ||||
|      Map.merge( | ||||
|        %{ | ||||
|          cipher: :rabbit_pbe.default_cipher(), | ||||
|          hash: :rabbit_pbe.default_hash(), | ||||
|          iterations: :rabbit_pbe.default_iterations() | ||||
|        }, | ||||
|        opts | ||||
|      )} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) when length(args) < 2 do | ||||
|       {:validation_failure, | ||||
|        {:bad_argument, "Please provide a value to decode and a passphrase."}} | ||||
|     {:validation_failure, {:bad_argument, "Please provide a value to decode and a passphrase."}} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) when length(args) > 2 do | ||||
|       {:validation_failure, :too_many_args} | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, opts) when length(args) === 2 do | ||||
|     case {supports_cipher(opts.cipher), supports_hash(opts.hash), opts.iterations > 0} do | ||||
|       {false, _, _}      -> {:validation_failure, {:bad_argument, "The requested cipher is not supported."}} | ||||
|       {_, false, _}      -> {:validation_failure, {:bad_argument, "The requested hash is not supported"}} | ||||
|       {_, _, false}      -> {:validation_failure, {:bad_argument, "The requested number of iterations is incorrect"}} | ||||
|       {true, true, true} -> :ok | ||||
|       {false, _, _} -> | ||||
|         {:validation_failure, {:bad_argument, "The requested cipher is not supported."}} | ||||
| 
 | ||||
|       {_, false, _} -> | ||||
|         {:validation_failure, {:bad_argument, "The requested hash is not supported"}} | ||||
| 
 | ||||
|       {_, _, false} -> | ||||
|         {:validation_failure, {:bad_argument, "The requested number of iterations is incorrect"}} | ||||
| 
 | ||||
|       {true, true, true} -> | ||||
|         :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -58,14 +70,16 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EncodeCommand do | |||
|       term_value = Helpers.evaluate_input_as_term(value) | ||||
|       result = :rabbit_pbe.encrypt_term(cipher, hash, iterations, passphrase, term_value) | ||||
|       {:ok, {:encrypted, result}} | ||||
|     catch _, _ -> | ||||
|       {:error, "Error during cipher operation."} | ||||
|     catch | ||||
|       _, _ -> | ||||
|         {:error, "Error during cipher operation."} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def formatter(), do: RabbitMQ.CLI.Formatters.Erlang | ||||
| 
 | ||||
|   def usage, do: "encode value passphrase [--cipher cipher] [--hash hash] [--iterations iterations]" | ||||
|   def usage, | ||||
|     do: "encode value passphrase [--cipher cipher] [--hash hash] [--iterations iterations]" | ||||
| 
 | ||||
|   def banner([_, _], _) do | ||||
|     "Encrypting value ..." | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.EnvironmentCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -24,7 +23,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EnvironmentCommand do | |||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([_|_], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   def run([], %{node: node_name}) do | ||||
|  |  | |||
|  | @ -29,17 +29,18 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EvalCommand do | |||
| 
 | ||||
|   def validate([expr | _], _) do | ||||
|     case parse_expr(expr) do | ||||
|       {:ok, _}      -> :ok; | ||||
|       {:ok, _} -> :ok | ||||
|       {:error, err} -> {:validation_failure, err} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def run([expr | arguments],  %{node: node_name} = opts) do | ||||
|   def run([expr | arguments], %{node: node_name} = opts) do | ||||
|     {:ok, parsed} = parse_expr(expr) | ||||
|     bindings = make_bindings(arguments, opts) | ||||
| 
 | ||||
|     case :rabbit_misc.rpc_call(node_name, :erl_eval, :exprs, [parsed, bindings]) do | ||||
|       {:value, value, _} -> {:ok, value}; | ||||
|       err                -> err | ||||
|       {:value, value, _} -> {:ok, value} | ||||
|       err -> err | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -51,23 +52,26 @@ defmodule RabbitMQ.CLI.Ctl.Commands.EvalCommand do | |||
| 
 | ||||
|   defp make_bindings(arguments, opts) do | ||||
|     Enum.with_index(arguments, 1) | ||||
|     |> Enum.map(fn({val, index}) -> {String.to_atom("_#{index}"), val} end) | ||||
|     |> Enum.map(fn {val, index} -> {String.to_atom("_#{index}"), val} end) | ||||
|     |> Enum.concat(option_bindings(opts)) | ||||
|   end | ||||
| 
 | ||||
|   defp option_bindings(opts) do | ||||
|     Enum.to_list(opts) | ||||
|     |> Enum.map(fn({key, val}) -> {String.to_atom("_#{key}"), val} end) | ||||
|     |> Enum.map(fn {key, val} -> {String.to_atom("_#{key}"), val} end) | ||||
|   end | ||||
| 
 | ||||
|   defp parse_expr(expr) do | ||||
|     expr_str = to_charlist(expr) | ||||
| 
 | ||||
|     case :erl_scan.string(expr_str) do | ||||
|       {:ok, scanned, _} -> | ||||
|         case :erl_parse.parse_exprs(scanned) do | ||||
|           {:ok, parsed} -> {:ok, parsed}; | ||||
|           {:ok, parsed} -> {:ok, parsed} | ||||
|           {:error, err} -> {:error, format_parse_error(err)} | ||||
|         end; | ||||
|       {:error, err, _}  -> | ||||
|         end | ||||
| 
 | ||||
|       {:error, err, _} -> | ||||
|         {:error, format_parse_error(err)} | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ExecCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -44,6 +43,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ExecCommand do | |||
|     rescue | ||||
|       ex in SyntaxError -> | ||||
|         {:validation_failure, "SyntaxError: " <> Exception.message(ex)} | ||||
| 
 | ||||
|       _ -> | ||||
|         :ok | ||||
|     end | ||||
|  | @ -53,8 +53,9 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ExecCommand do | |||
|     try do | ||||
|       {val, _} = Code.eval_string(expr, [options: opts], __ENV__) | ||||
|       {:ok, val} | ||||
|     rescue ex -> | ||||
|       {:error, Exception.message(ex)} | ||||
|     rescue | ||||
|       ex -> | ||||
|         {:error, Exception.message(ex)} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ForceBootCommand do | |||
|   def validate(args, _) when length(args) > 0 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], %{}), do: :ok | ||||
| 
 | ||||
|   ## | ||||
|  | @ -38,21 +39,22 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ForceBootCommand do | |||
|   end | ||||
| 
 | ||||
|   def run([], %{node: node_name} = opts) do | ||||
|     case :rabbit_misc.rpc_call(node_name, | ||||
|                                :rabbit_mnesia, :force_load_next_boot, []) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :force_load_next_boot, []) do | ||||
|       {:badrpc, :nodedown} -> | ||||
|         case Config.get_option(:mnesia_dir, opts) do | ||||
|           nil        -> | ||||
|             {:error, :mnesia_dir_not_found}; | ||||
|           nil -> | ||||
|             {:error, :mnesia_dir_not_found} | ||||
| 
 | ||||
|           dir -> | ||||
|             File.write(Path.join(dir, "force_load"), "") | ||||
|         end; | ||||
|       _ -> :ok | ||||
|         end | ||||
| 
 | ||||
|       _ -> | ||||
|         :ok | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "force_boot" | ||||
| 
 | ||||
|   def banner(_, _), do: nil | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,13 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ForceResetCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppStopped | ||||
|  | @ -30,12 +29,12 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ForceResetCommand do | |||
| 
 | ||||
|   def usage, do: "force_reset" | ||||
| 
 | ||||
| 
 | ||||
|   def banner(_, %{node: node_name}), do: "Forcefully resetting node #{node_name} ..." | ||||
| 
 | ||||
|   def output({:error, :mnesia_unexpectedly_running}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      RabbitMQ.CLI.DefaultOutput.mnesia_running_error(node_name)} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -26,17 +26,21 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ForgetClusterNodeCommand do | |||
|     {args, Map.merge(%{offline: false}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_,_|_], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_, _ | _], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
| 
 | ||||
|   def validate_execution_environment([_node_to_remove] = args, %{offline: true} = opts) do | ||||
|     Validators.chain([&Validators.node_is_not_running/2, | ||||
|                       &Validators.mnesia_dir_is_set/2, | ||||
|                       &Validators.rabbit_is_loaded/2], | ||||
|                      [args, opts]) | ||||
|     Validators.chain( | ||||
|       [ | ||||
|         &Validators.node_is_not_running/2, | ||||
|         &Validators.mnesia_dir_is_set/2, | ||||
|         &Validators.rabbit_is_loaded/2 | ||||
|       ], | ||||
|       [args, opts] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def validate_execution_environment([_], %{offline: false}) do | ||||
|     :ok | ||||
|   end | ||||
|  | @ -44,16 +48,18 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ForgetClusterNodeCommand do | |||
|   def run([node_to_remove], %{node: node_name, offline: true} = opts) do | ||||
|     Stream.concat([ | ||||
|       become(node_name, opts), | ||||
|       RabbitMQ.CLI.Core.Helpers.defer(fn() -> | ||||
|       RabbitMQ.CLI.Core.Helpers.defer(fn -> | ||||
|         :rabbit_event.start_link() | ||||
|         :rabbit_mnesia.forget_cluster_node(to_atom(node_to_remove), true) | ||||
|       end)]) | ||||
|       end) | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def run([node_to_remove], %{node: node_name, offline: false}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|                           :rabbit_mnesia, :forget_cluster_node, | ||||
|                           [to_atom(node_to_remove), false]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :forget_cluster_node, [ | ||||
|       to_atom(node_to_remove), | ||||
|       false | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|  | @ -64,22 +70,27 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ForgetClusterNodeCommand do | |||
|     "Removing node #{node_to_remove} from the cluster" | ||||
|   end | ||||
| 
 | ||||
| 
 | ||||
|   defp become(node_name, opts) do | ||||
|     :error_logger.tty(false) | ||||
| 
 | ||||
|     case :net_adm.ping(node_name) do | ||||
|         :pong -> exit({:node_running, node_name}); | ||||
|         :pang -> :ok = :net_kernel.stop() | ||||
|                  Stream.concat([ | ||||
|                    ["  * Impersonating node: #{node_name}..."], | ||||
|                    RabbitMQ.CLI.Core.Helpers.defer(fn() -> | ||||
|                      {:ok, _} = Distribution.start_as(node_name, opts) | ||||
|                      " done" | ||||
|                    end), | ||||
|                    RabbitMQ.CLI.Core.Helpers.defer(fn() -> | ||||
|                      dir = :mnesia.system_info(:directory) | ||||
|                      "  * Mnesia directory: #{dir}..." | ||||
|                    end)]) | ||||
|       :pong -> | ||||
|         exit({:node_running, node_name}) | ||||
| 
 | ||||
|       :pang -> | ||||
|         :ok = :net_kernel.stop() | ||||
| 
 | ||||
|         Stream.concat([ | ||||
|           ["  * Impersonating node: #{node_name}..."], | ||||
|           RabbitMQ.CLI.Core.Helpers.defer(fn -> | ||||
|             {:ok, _} = Distribution.start_as(node_name, opts) | ||||
|             " done" | ||||
|           end), | ||||
|           RabbitMQ.CLI.Core.Helpers.defer(fn -> | ||||
|             dir = :mnesia.system_info(:directory) | ||||
|             "  * Mnesia directory: #{dir}..." | ||||
|           end) | ||||
|         ]) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,9 +13,7 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.HelpCommand do | ||||
| 
 | ||||
|   alias RabbitMQ.CLI.Core.{CommandModules, Config, ExitCodes} | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|  | @ -30,27 +28,34 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HelpCommand do | |||
| 
 | ||||
|   def switches(), do: [list_commands: :boolean] | ||||
| 
 | ||||
|   def run([command_name|_], opts) do | ||||
|   def run([command_name | _], opts) do | ||||
|     CommandModules.load(opts) | ||||
|     case CommandModules.module_map[command_name] do | ||||
| 
 | ||||
|     case CommandModules.module_map()[command_name] do | ||||
|       nil -> | ||||
|         all_usage(opts); | ||||
|         all_usage(opts) | ||||
| 
 | ||||
|       command -> | ||||
|         Enum.join([base_usage(command, opts)] ++ | ||||
|                   options_usage() ++ | ||||
|                   additional_usage(command), "\n\n") | ||||
|         Enum.join( | ||||
|           [base_usage(command, opts)] ++ | ||||
|             options_usage() ++ | ||||
|             additional_usage(command), | ||||
|           "\n\n" | ||||
|         ) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def run(_, opts) do | ||||
|     CommandModules.load(opts) | ||||
| 
 | ||||
|     case opts[:list_commands] do | ||||
|       true  -> commands(); | ||||
|       _     -> all_usage(opts) | ||||
|       true -> commands() | ||||
|       _ -> all_usage(opts) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def output(result, _) do | ||||
|     {:error, ExitCodes.exit_ok, result} | ||||
|     {:error, ExitCodes.exit_ok(), result} | ||||
|   end | ||||
| 
 | ||||
|   def program_name(opts) do | ||||
|  | @ -58,35 +63,46 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HelpCommand do | |||
|   end | ||||
| 
 | ||||
|   def all_usage(opts) do | ||||
|     Enum.join(tool_usage(program_name(opts)) ++ | ||||
|               options_usage() ++ | ||||
|               [Enum.join(["Commands:"] ++ commands(), "\n")] ++ | ||||
|               additional_usage(), "\n\n") | ||||
|     Enum.join( | ||||
|       tool_usage(program_name(opts)) ++ | ||||
|         options_usage() ++ | ||||
|         [Enum.join(["Commands:"] ++ commands(), "\n")] ++ | ||||
|         additional_usage(), | ||||
|       "\n\n" | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage(), do: "help (<command> | [--list-commands])" | ||||
| 
 | ||||
|   defp tool_usage(tool_name) do | ||||
|     ["\nUsage:\n" <> | ||||
|      "#{tool_name} [-n <node>] [-t <timeout>] [-l] [-q] <command> [<command options>]"] | ||||
|     [ | ||||
|       "\nUsage:\n" <> | ||||
|         "#{tool_name} [-n <node>] [-t <timeout>] [-l] [-q] <command> [<command options>]" | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|   def base_usage(command, opts) do | ||||
|     tool_name = program_name(opts) | ||||
|     maybe_timeout = case command_supports_timeout(command) do | ||||
|       true  -> " [-t <timeout>]" | ||||
|       false -> "" | ||||
|     end | ||||
|     Enum.join(["\nUsage:\n", | ||||
|                "#{tool_name} [-n <node>] [-l] [-q] " <> | ||||
|                flatten_string(command.usage(), maybe_timeout)]) | ||||
| 
 | ||||
|     maybe_timeout = | ||||
|       case command_supports_timeout(command) do | ||||
|         true -> " [-t <timeout>]" | ||||
|         false -> "" | ||||
|       end | ||||
| 
 | ||||
|     Enum.join([ | ||||
|       "\nUsage:\n", | ||||
|       "#{tool_name} [-n <node>] [-l] [-q] " <> | ||||
|         flatten_string(command.usage(), maybe_timeout) | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   defp flatten_string(list, additional) when is_list(list) do | ||||
|     list | ||||
|     |> Enum.map(fn(line) -> line <> additional end) | ||||
|     |> Enum.map(fn line -> line <> additional end) | ||||
|     |> Enum.join("\n") | ||||
|   end | ||||
| 
 | ||||
|   defp flatten_string(str, additional) when is_binary(str) do | ||||
|     str <> additional | ||||
|   end | ||||
|  | @ -125,36 +141,43 @@ to display results. The default value is \"/\"."] | |||
|   def commands() do | ||||
|     # Enum.map obtains the usage string for each command module. | ||||
|     # Enum.each prints them all. | ||||
|     CommandModules.module_map | ||||
|     |>  Map.values | ||||
|     |>  Enum.sort | ||||
|     |>  Enum.map( fn(cmd) -> | ||||
|                     maybe_timeout = case command_supports_timeout(cmd) do | ||||
|                       true  -> " [-t <timeout>]" | ||||
|                       false -> "" | ||||
|                     end | ||||
|                     case cmd.usage() do | ||||
|                       bin when is_binary(bin) -> | ||||
|                         bin <> maybe_timeout; | ||||
|                       list when is_list(list) -> | ||||
|                         Enum.map(list, fn(line) -> line <> maybe_timeout end) | ||||
|                     end | ||||
|                   end) | ||||
|     |>  List.flatten | ||||
|     |>  Enum.sort | ||||
|     |>  Enum.map(fn(cmd_usage) -> "    #{cmd_usage}" end) | ||||
|     CommandModules.module_map() | ||||
|     |> Map.values() | ||||
|     |> Enum.sort() | ||||
|     |> Enum.map(fn cmd -> | ||||
|       maybe_timeout = | ||||
|         case command_supports_timeout(cmd) do | ||||
|           true -> " [-t <timeout>]" | ||||
|           false -> "" | ||||
|         end | ||||
| 
 | ||||
|       case cmd.usage() do | ||||
|         bin when is_binary(bin) -> | ||||
|           bin <> maybe_timeout | ||||
| 
 | ||||
|         list when is_list(list) -> | ||||
|           Enum.map(list, fn line -> line <> maybe_timeout end) | ||||
|       end | ||||
|     end) | ||||
|     |> List.flatten() | ||||
|     |> Enum.sort() | ||||
|     |> Enum.map(fn cmd_usage -> "    #{cmd_usage}" end) | ||||
|   end | ||||
| 
 | ||||
|   defp additional_usage(command) do | ||||
|     if :erlang.function_exported(command, :usage_additional, 0) do | ||||
|       case command.usage_additional() do | ||||
|         list when is_list(list) -> ["<timeout> - operation timeout in seconds. Default is \"infinity\"." | list]; | ||||
|         bin when is_binary(bin) -> ["<timeout> - operation timeout in seconds. Default is \"infinity\".", bin] | ||||
|         list when is_list(list) -> | ||||
|           ["<timeout> - operation timeout in seconds. Default is \"infinity\"." | list] | ||||
| 
 | ||||
|         bin when is_binary(bin) -> | ||||
|           ["<timeout> - operation timeout in seconds. Default is \"infinity\".", bin] | ||||
|       end | ||||
|     else | ||||
|       case command_supports_timeout(command) do | ||||
|         true -> | ||||
|           ["<timeout> - operation timeout in seconds. Default is \"infinity\"."]; | ||||
|           ["<timeout> - operation timeout in seconds. Default is \"infinity\"."] | ||||
| 
 | ||||
|         false -> | ||||
|           [] | ||||
|       end | ||||
|  | @ -162,20 +185,22 @@ to display results. The default value is \"/\"."] | |||
|   end | ||||
| 
 | ||||
|   defp additional_usage() do | ||||
|     ["<timeout> - operation timeout in seconds. Default is \"infinity\".", | ||||
|      CommandModules.module_map | ||||
|      |> Map.values | ||||
|      |> Enum.filter(&:erlang.function_exported(&1, :usage_additional, 0)) | ||||
|      |> Enum.map(&(&1.usage_additional)) | ||||
|      |> Enum.join("\n\n")] | ||||
|     [ | ||||
|       "<timeout> - operation timeout in seconds. Default is \"infinity\".", | ||||
|       CommandModules.module_map() | ||||
|       |> Map.values() | ||||
|       |> Enum.filter(&:erlang.function_exported(&1, :usage_additional, 0)) | ||||
|       |> Enum.map(& &1.usage_additional) | ||||
|       |> Enum.join("\n\n") | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|   defp command_supports_timeout(command) do | ||||
|     case :erlang.function_exported(command, :switches, 0) do | ||||
|       true  -> nil != command.switches[:timeout]; | ||||
|       true -> nil != command.switches[:timeout] | ||||
|       false -> false | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def banner(_,_), do: nil | ||||
|   def banner(_, _), do: nil | ||||
| end | ||||
|  |  | |||
|  | @ -31,29 +31,37 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HipeCompileCommand do | |||
| 
 | ||||
|   def usage, do: "hipe_compile <directory>" | ||||
| 
 | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
| 
 | ||||
|   def validate([target_dir], opts) do | ||||
|     :ok | ||||
|     |> Helpers.validate_step(fn() -> | ||||
|     |> Helpers.validate_step(fn -> | ||||
|       case acceptable_path?(target_dir) do | ||||
|         true  -> :ok | ||||
|         true -> :ok | ||||
|         false -> {:error, {:bad_argument, "Target directory path cannot be blank"}} | ||||
|       end | ||||
|     end) | ||||
|     |> Helpers.validate_step(fn() -> | ||||
|     |> Helpers.validate_step(fn -> | ||||
|       case File.dir?(target_dir) do | ||||
|         true  -> :ok | ||||
|         true -> | ||||
|           :ok | ||||
| 
 | ||||
|         false -> | ||||
|           case File.mkdir_p(target_dir) do | ||||
|             :ok              -> :ok | ||||
|             :ok -> | ||||
|               :ok | ||||
| 
 | ||||
|             {:error, perm} when perm == :eperm or perm == :eacces -> | ||||
|               {:error, {:bad_argument, "Cannot create target directory #{target_dir}: insufficient permissions"}} | ||||
|               {:error, | ||||
|                {:bad_argument, | ||||
|                 "Cannot create target directory #{target_dir}: insufficient permissions"}} | ||||
|           end | ||||
|       end | ||||
|     end) | ||||
|     |> Helpers.validate_step(fn() -> Helpers.require_rabbit(opts) end) | ||||
|     |> Helpers.validate_step(fn -> Helpers.require_rabbit(opts) end) | ||||
|   end | ||||
|   def validate(_, _),   do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   def validate(_, _), do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   def run([target_dir], _opts) do | ||||
|     Code.ensure_loaded(:rabbit_hipe) | ||||
|  | @ -77,10 +85,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.HipeCompileCommand do | |||
|     case :rabbit_hipe.can_hipe_compile() do | ||||
|       true -> | ||||
|         case :rabbit_hipe.compile_to_directory(target_dir) do | ||||
|           {:ok, _, _}              -> :ok | ||||
|           {:ok, _, _} -> :ok | ||||
|           {:ok, :already_compiled} -> {:ok, "already compiled"} | ||||
|           {:error, message}        -> {:error, message} | ||||
|           {:error, message} -> {:error, message} | ||||
|         end | ||||
| 
 | ||||
|       false -> | ||||
|         {:error, "HiPE compilation is not supported"} | ||||
|     end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is Pivotal Software, Inc. | ||||
| ## Copyright (c) 2016-2017 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.JoinClusterCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -31,27 +30,30 @@ defmodule RabbitMQ.CLI.Ctl.Commands.JoinClusterCommand do | |||
|   end | ||||
| 
 | ||||
|   def validate(_, %{disc: true, ram: true}) do | ||||
|     {:validation_failure, | ||||
|      {:bad_argument, "The node type must be either disc or ram."}} | ||||
|     {:validation_failure, {:bad_argument, "The node type must be either disc or ram."}} | ||||
|   end | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
| 
 | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_], _), do: :ok | ||||
|   def validate(_, _),   do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppStopped | ||||
| 
 | ||||
|   def run([target_node], %{node: node_name, ram: ram, disc: disc}) do | ||||
|     node_type = case {ram, disc} do | ||||
|       {true, false}  -> :ram | ||||
|       {false, true}  -> :disc | ||||
|       ## disc is default | ||||
|       {false, false} -> :disc | ||||
|     end | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|         :rabbit_mnesia, | ||||
|         :join_cluster, | ||||
|         [Helpers.normalise_node(target_node), node_type] | ||||
|       ) | ||||
|     node_type = | ||||
|       case {ram, disc} do | ||||
|         {true, false} -> :ram | ||||
|         {false, true} -> :disc | ||||
|         ## disc is default | ||||
|         {false, false} -> :disc | ||||
|       end | ||||
| 
 | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_mnesia, | ||||
|       :join_cluster, | ||||
|       [Helpers.normalise_node(target_node), node_type] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|  | @ -65,13 +67,16 @@ defmodule RabbitMQ.CLI.Ctl.Commands.JoinClusterCommand do | |||
|   def output({:ok, :already_member}, _) do | ||||
|     {:ok, "The node is already a member of this cluster"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :mnesia_unexpectedly_running}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      RabbitMQ.CLI.DefaultOutput.mnesia_running_error(node_name)} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :cannot_cluster_node_with_itself}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      "Error: cannot cluster node with itself: #{node_name}"} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListBindingsCommand do | ||||
|   alias RabbitMQ.CLI.Ctl.{InfoKeys, RpcStream} | ||||
| 
 | ||||
|  | @ -35,42 +34,48 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListBindingsCommand do | |||
|     merge_defaults( | ||||
|       ~w(source_name source_kind | ||||
|         destination_name destination_kind | ||||
|         routing_key arguments), opts) | ||||
|         routing_key arguments), | ||||
|       opts | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(default_opts(), opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) do | ||||
|       case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|         {:ok, _} -> :ok | ||||
|         err -> err | ||||
|       end | ||||
|     case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|       {:ok, _} -> :ok | ||||
|       err -> err | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_|_] = args, %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|       info_keys = InfoKeys.prepare_info_keys(args) | ||||
|   def run([_ | _] = args, %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     info_keys = InfoKeys.prepare_info_keys(args) | ||||
| 
 | ||||
|       RpcStream.receive_list_items(node_name, :rabbit_binding, :info_all, | ||||
|         [vhost, info_keys], | ||||
|         timeout, | ||||
|         info_keys) | ||||
|     RpcStream.receive_list_items( | ||||
|       node_name, | ||||
|       :rabbit_binding, | ||||
|       :info_all, | ||||
|       [vhost, info_keys], | ||||
|       timeout, | ||||
|       info_keys | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|       "list_bindings [-p <vhost>] [--no-table-headers] [<bindinginfoitem> ...]" | ||||
|     "list_bindings [-p <vhost>] [--no-table-headers] [<bindinginfoitem> ...]" | ||||
|   end | ||||
| 
 | ||||
|   def usage_additional() do | ||||
|       "<bindinginfoitem> must be a member of the list [" <> | ||||
|     "<bindinginfoitem> must be a member of the list [" <> | ||||
|       Enum.join(@info_keys, ", ") <> "]." | ||||
|   end | ||||
| 
 | ||||
|   defp default_opts() do | ||||
|     %{vhost: "/", | ||||
|       table_headers: true} | ||||
|     %{vhost: "/", table_headers: true} | ||||
|   end | ||||
| 
 | ||||
|   def banner(_, %{vhost: vhost}), do: "Listing bindings for vhost #{vhost}..." | ||||
|  |  | |||
|  | @ -14,7 +14,6 @@ | |||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| ## | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListChannelsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
|   alias RabbitMQ.CLI.Ctl.{InfoKeys, RpcStream} | ||||
|  | @ -37,41 +36,46 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListChannelsCommand do | |||
|   def merge_defaults([], opts) do | ||||
|     merge_defaults(~w(pid user consumer_count messages_unacknowledged), opts) | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) do | ||||
|       case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|         {:ok, _} -> :ok | ||||
|         err -> err | ||||
|       end | ||||
|     case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|       {:ok, _} -> :ok | ||||
|       err -> err | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], opts) do | ||||
|       run(~w(pid user consumer_count messages_unacknowledged), opts) | ||||
|     run(~w(pid user consumer_count messages_unacknowledged), opts) | ||||
|   end | ||||
| 
 | ||||
|   def run([_|_] = args, %{node: node_name, timeout: timeout}) do | ||||
|       info_keys = InfoKeys.prepare_info_keys(args) | ||||
|       Helpers.with_nodes_in_cluster(node_name, fn(nodes) -> | ||||
|         RpcStream.receive_list_items(node_name, | ||||
|                                      :rabbit_channel, :emit_info_all, | ||||
|                                      [nodes, info_keys], | ||||
|                                      timeout, | ||||
|                                      info_keys, | ||||
|                                      Kernel.length(nodes)) | ||||
|       end) | ||||
|   def run([_ | _] = args, %{node: node_name, timeout: timeout}) do | ||||
|     info_keys = InfoKeys.prepare_info_keys(args) | ||||
| 
 | ||||
|     Helpers.with_nodes_in_cluster(node_name, fn nodes -> | ||||
|       RpcStream.receive_list_items( | ||||
|         node_name, | ||||
|         :rabbit_channel, | ||||
|         :emit_info_all, | ||||
|         [nodes, info_keys], | ||||
|         timeout, | ||||
|         info_keys, | ||||
|         Kernel.length(nodes) | ||||
|       ) | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|       "list_channels [--no-table-headers] [<channelinfoitem> ...]" | ||||
|     "list_channels [--no-table-headers] [<channelinfoitem> ...]" | ||||
|   end | ||||
| 
 | ||||
|   def usage_additional() do | ||||
|       "<channelinfoitem> must be a member of the list [" <> | ||||
|     "<channelinfoitem> must be a member of the list [" <> | ||||
|       Enum.join(@info_keys, ", ") <> "]." | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,10 +20,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListCiphersCommand do | |||
|   def merge_defaults(args, opts) do | ||||
|     {args, opts} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) when length(args) > 0 do | ||||
|       {:validation_failure, | ||||
|        {:bad_argument, :too_many_args}} | ||||
|     {:validation_failure, {:bad_argument, :too_many_args}} | ||||
|   end | ||||
| 
 | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   def distribution(_), do: :none | ||||
|  | @ -37,5 +38,4 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListCiphersCommand do | |||
|   def usage, do: "list_ciphers" | ||||
| 
 | ||||
|   def banner(_, _), do: "Listing supported ciphers ..." | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListConnectionsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
|   alias RabbitMQ.CLI.Ctl.{InfoKeys, RpcStream} | ||||
|  | @ -39,38 +38,42 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListConnectionsCommand do | |||
|   def merge_defaults([], opts) do | ||||
|     merge_defaults(~w(user peer_host peer_port state), opts) | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) do | ||||
|       case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|         {:ok, _} -> :ok | ||||
|         err -> err | ||||
|       end | ||||
|     case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|       {:ok, _} -> :ok | ||||
|       err -> err | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_|_] = args, %{node: node_name, timeout: timeout}) do | ||||
|       info_keys = InfoKeys.prepare_info_keys(args) | ||||
|       Helpers.with_nodes_in_cluster(node_name, fn(nodes) -> | ||||
|         RpcStream.receive_list_items(node_name, | ||||
|                                      :rabbit_networking, | ||||
|                                      :emit_connection_info_all, | ||||
|                                      [nodes, info_keys], | ||||
|                                      timeout, | ||||
|                                      info_keys, | ||||
|                                      Kernel.length(nodes)) | ||||
|       end) | ||||
|   def run([_ | _] = args, %{node: node_name, timeout: timeout}) do | ||||
|     info_keys = InfoKeys.prepare_info_keys(args) | ||||
| 
 | ||||
|     Helpers.with_nodes_in_cluster(node_name, fn nodes -> | ||||
|       RpcStream.receive_list_items( | ||||
|         node_name, | ||||
|         :rabbit_networking, | ||||
|         :emit_connection_info_all, | ||||
|         [nodes, info_keys], | ||||
|         timeout, | ||||
|         info_keys, | ||||
|         Kernel.length(nodes) | ||||
|       ) | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|       "list_connections [--no-table-headers] [<connectioninfoitem> ...]" | ||||
|     "list_connections [--no-table-headers] [<connectioninfoitem> ...]" | ||||
|   end | ||||
| 
 | ||||
|   def usage_additional() do | ||||
|       "<connectioninfoitem> must be a member of the list [" <> | ||||
|     "<connectioninfoitem> must be a member of the list [" <> | ||||
|       Enum.join(@info_keys, ", ") <> "]." | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,7 +32,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListConsumersCommand do | |||
|   def info_keys(), do: @info_keys | ||||
| 
 | ||||
|   def merge_defaults([], opts) do | ||||
|     {Enum.map(@info_keys -- [:activity_status], &Atom.to_string/1), Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|     {Enum.map(@info_keys -- [:activity_status], &Atom.to_string/1), | ||||
|      Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|  | @ -50,6 +51,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListConsumersCommand do | |||
| 
 | ||||
|   def run([_ | _] = args, %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     info_keys = InfoKeys.prepare_info_keys(args) | ||||
| 
 | ||||
|     Helpers.with_nodes_in_cluster(node_name, fn nodes -> | ||||
|       RpcStream.receive_list_items( | ||||
|         node_name, | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListExchangesCommand do | ||||
|   alias RabbitMQ.CLI.Ctl.{InfoKeys, RpcStream} | ||||
| 
 | ||||
|  | @ -39,30 +38,35 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListExchangesCommand do | |||
|   end | ||||
| 
 | ||||
|   def validate(args, _) do | ||||
|       case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|         {:ok, _} -> :ok | ||||
|         err -> err | ||||
|       end | ||||
|     case InfoKeys.validate_info_keys(args, @info_keys) do | ||||
|       {:ok, _} -> :ok | ||||
|       err -> err | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_|_] = args, %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|       info_keys = InfoKeys.prepare_info_keys(args) | ||||
|       RpcStream.receive_list_items(node_name, :rabbit_exchange, :info_all, | ||||
|         [vhost, info_keys], | ||||
|         timeout, | ||||
|         info_keys) | ||||
|   def run([_ | _] = args, %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     info_keys = InfoKeys.prepare_info_keys(args) | ||||
| 
 | ||||
|     RpcStream.receive_list_items( | ||||
|       node_name, | ||||
|       :rabbit_exchange, | ||||
|       :info_all, | ||||
|       [vhost, info_keys], | ||||
|       timeout, | ||||
|       info_keys | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|       "list_exchanges [-p <vhost>] [--no-table-headers] [<exchangeinfoitem> ...]" | ||||
|     "list_exchanges [-p <vhost>] [--no-table-headers] [<exchangeinfoitem> ...]" | ||||
|   end | ||||
| 
 | ||||
|   def usage_additional() do | ||||
|       "<exchangeinfoitem> must be a member of the list [" <> | ||||
|     "<exchangeinfoitem> must be a member of the list [" <> | ||||
|       Enum.join(@info_keys, ", ") <> "]." | ||||
|   end | ||||
| 
 | ||||
|   def banner(_,%{vhost: vhost}), do: "Listing exchanges for vhost #{vhost} ..." | ||||
|   def banner(_, %{vhost: vhost}), do: "Listing exchanges for vhost #{vhost} ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListGlobalParametersCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -28,23 +27,25 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListGlobalParametersCommand do | |||
|   def switches(), do: [timeout: :integer, table_headers: :boolean] | ||||
|   def aliases(), do: [t: :timeout] | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_runtime_parameters, | ||||
|       :list_global_formatted, | ||||
|       [], | ||||
|       timeout) | ||||
|       timeout | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "list_global_parameters [--no-table-headers]" | ||||
| 
 | ||||
|   def banner(_, _), do: "Listing global runtime parameters ..." | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -20,10 +20,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListHashesCommand do | |||
|   def merge_defaults(args, opts) do | ||||
|     {args, opts} | ||||
|   end | ||||
| 
 | ||||
|   def validate(args, _) when length(args) > 0 do | ||||
|       {:validation_failure, | ||||
|        {:bad_argument, :too_many_args}} | ||||
|     {:validation_failure, {:bad_argument, :too_many_args}} | ||||
|   end | ||||
| 
 | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   def distribution(_), do: :none | ||||
|  | @ -37,5 +38,4 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListHashesCommand do | |||
|   def usage, do: "list_hashes" | ||||
| 
 | ||||
|   def banner(_, _), do: "Listing supported hash algorithms ..." | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListOperatorPoliciesCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -28,23 +27,26 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListOperatorPoliciesCommand do | |||
|     {args, Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_policy, | ||||
|       :list_formatted_op, | ||||
|       [vhost], | ||||
|       timeout) | ||||
|       timeout | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "list_operator_policies [-p <vhost>] [--no-table-headers]" | ||||
| 
 | ||||
|   def banner(_, %{vhost: vhost}), do: "Listing operator policy overrides for vhost \"#{vhost}\" ..." | ||||
| 
 | ||||
|   def banner(_, %{vhost: vhost}), | ||||
|     do: "Listing operator policy overrides for vhost \"#{vhost}\" ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListParametersCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -29,17 +28,20 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListParametersCommand do | |||
|     {args, Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_runtime_parameters, | ||||
|       :list_formatted, | ||||
|       [vhost], | ||||
|       timeout) | ||||
|       timeout | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "list_parameters [-p <vhost>] [--no-table-headers]" | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListPermissionsCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -28,15 +27,17 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListPermissionsCommand do | |||
|     {args, Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :list_vhost_permissions, | ||||
|       [vhost], | ||||
|  | @ -47,5 +48,4 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListPermissionsCommand do | |||
|   def usage, do: "list_permissions [-p <vhost>] [--no-table-headers]" | ||||
| 
 | ||||
|   def banner(_, %{vhost: vhost}), do: "Listing permissions for vhost \"#{vhost}\" ..." | ||||
| 
 | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListPoliciesCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -28,19 +27,22 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListPoliciesCommand do | |||
|     {args, Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_policy, | ||||
|       :list_formatted, | ||||
|       [vhost], | ||||
|       timeout) | ||||
|       timeout | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "list_policies [-p <vhost>] [--no-table-headers]" | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListQueuesCommand do | ||||
|   require RabbitMQ.CLI.Ctl.InfoKeys | ||||
|   require RabbitMQ.CLI.Ctl.RpcStream | ||||
|  | @ -40,27 +39,36 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListQueuesCommand do | |||
| 
 | ||||
|   def scopes(), do: [:ctl, :diagnostics] | ||||
| 
 | ||||
|   def switches(), do: [offline: :boolean, online: :boolean, local: :boolean, timeout: :integer, | ||||
|                        table_headers: :boolean] | ||||
|   def switches(), | ||||
|     do: [ | ||||
|       offline: :boolean, | ||||
|       online: :boolean, | ||||
|       local: :boolean, | ||||
|       timeout: :integer, | ||||
|       table_headers: :boolean | ||||
|     ] | ||||
| 
 | ||||
|   def aliases(), do: [t: :timeout] | ||||
| 
 | ||||
|   defp default_opts() do | ||||
|     %{vhost: "/", | ||||
|       offline: false, | ||||
|       online: false, | ||||
|       local: false, | ||||
|       table_headers: true} | ||||
|     %{vhost: "/", offline: false, online: false, local: false, table_headers: true} | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults([_|_] = args, opts) do | ||||
|     timeout = case opts[:timeout] do | ||||
|       nil       -> @default_timeout; | ||||
|       :infinity -> @default_timeout; | ||||
|       other     -> other | ||||
|     end | ||||
|     {args, Map.merge(default_opts(), | ||||
|         Map.merge(opts, %{timeout: timeout}))} | ||||
|   def merge_defaults([_ | _] = args, opts) do | ||||
|     timeout = | ||||
|       case opts[:timeout] do | ||||
|         nil -> @default_timeout | ||||
|         :infinity -> @default_timeout | ||||
|         other -> other | ||||
|       end | ||||
| 
 | ||||
|     {args, | ||||
|      Map.merge( | ||||
|        default_opts(), | ||||
|        Map.merge(opts, %{timeout: timeout}) | ||||
|      )} | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults([], opts) do | ||||
|     merge_defaults(~w(name messages), opts) | ||||
|   end | ||||
|  | @ -76,30 +84,47 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListQueuesCommand do | |||
|   # it lists queues with unavailable masters | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_|_] = args, %{node: node_name, timeout: timeout, vhost: vhost, | ||||
|                           online: online_opt, offline: offline_opt, | ||||
|                           local: local_opt}) do | ||||
|     {online, offline} = case {online_opt, offline_opt} do | ||||
|         {false, false} -> {true, true}; | ||||
|         other          -> other | ||||
|     end | ||||
|   def run([_ | _] = args, %{ | ||||
|         node: node_name, | ||||
|         timeout: timeout, | ||||
|         vhost: vhost, | ||||
|         online: online_opt, | ||||
|         offline: offline_opt, | ||||
|         local: local_opt | ||||
|       }) do | ||||
|     {online, offline} = | ||||
|       case {online_opt, offline_opt} do | ||||
|         {false, false} -> {true, true} | ||||
|         other -> other | ||||
|       end | ||||
| 
 | ||||
|     info_keys = InfoKeys.prepare_info_keys(args) | ||||
|     Helpers.with_nodes_in_cluster(node_name, fn(nodes) -> | ||||
| 
 | ||||
|     Helpers.with_nodes_in_cluster(node_name, fn nodes -> | ||||
|       offline_mfa = {:rabbit_amqqueue, :emit_info_down, [vhost, info_keys]} | ||||
|       local_mfa = {:rabbit_amqqueue, :emit_info_local, [vhost, info_keys]} | ||||
|       online_mfa  = {:rabbit_amqqueue, :emit_info_all, [nodes, vhost, info_keys]} | ||||
|       {chunks, mfas} = case {local_opt, offline, online} do | ||||
|         # Local takes precedence | ||||
|         {true, _, _}      -> {1, [local_mfa]}; | ||||
|         {_, true, true}   -> {Kernel.length(nodes) + 1, [offline_mfa, online_mfa]}; | ||||
|         {_, false, true}  -> {Kernel.length(nodes), [online_mfa]}; | ||||
|         {_, true, false}  -> {1, [offline_mfa]} | ||||
|       end | ||||
|       RpcStream.receive_list_items_with_fun(node_name, mfas, timeout, info_keys, chunks, | ||||
|         fn({{:error, {:badrpc, {:timeout, to}}}, :finished}) -> | ||||
|           {{:error, {:badrpc, {:timeout, to, "Some queue(s) are unresponsive, use list_unresponsive_queues command."}}}, :finished}; | ||||
|           (any) -> any | ||||
|         end) | ||||
|       online_mfa = {:rabbit_amqqueue, :emit_info_all, [nodes, vhost, info_keys]} | ||||
| 
 | ||||
|       {chunks, mfas} = | ||||
|         case {local_opt, offline, online} do | ||||
|           # Local takes precedence | ||||
|           {true, _, _} -> {1, [local_mfa]} | ||||
|           {_, true, true} -> {Kernel.length(nodes) + 1, [offline_mfa, online_mfa]} | ||||
|           {_, false, true} -> {Kernel.length(nodes), [online_mfa]} | ||||
|           {_, true, false} -> {1, [offline_mfa]} | ||||
|         end | ||||
| 
 | ||||
|       RpcStream.receive_list_items_with_fun(node_name, mfas, timeout, info_keys, chunks, fn | ||||
|         {{:error, {:badrpc, {:timeout, to}}}, :finished} -> | ||||
|           {{:error, | ||||
|             {:badrpc, | ||||
|              {:timeout, to, | ||||
|               "Some queue(s) are unresponsive, use list_unresponsive_queues command."}}}, | ||||
|            :finished} | ||||
| 
 | ||||
|         any -> | ||||
|           any | ||||
|       end) | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
|  | @ -111,8 +136,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListQueuesCommand do | |||
|     ["<queueinfoitem> must be a member of the list [" <> Enum.join(@info_keys, ", ") <> "]."] | ||||
|   end | ||||
| 
 | ||||
|   def banner(_,%{vhost: vhost, timeout: timeout}) do | ||||
|     ["Timeout: #{timeout / 1000} seconds ...", | ||||
|      "Listing queues for vhost #{vhost} ..."] | ||||
|   def banner(_, %{vhost: vhost, timeout: timeout}) do | ||||
|     ["Timeout: #{timeout / 1000} seconds ...", "Listing queues for vhost #{vhost} ..."] | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListTopicPermissionsCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -28,15 +27,17 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListTopicPermissionsCommand do | |||
|     {args, Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :list_vhost_topic_permissions, | ||||
|       [vhost], | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListUnresponsiveQueuesCommand do | ||||
|   require RabbitMQ.CLI.Ctl.InfoKeys | ||||
|   require RabbitMQ.CLI.Ctl.RpcStream | ||||
|  | @ -33,17 +32,19 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUnresponsiveQueuesCommand do | |||
| 
 | ||||
|   def scopes(), do: [:ctl, :diagnostics] | ||||
| 
 | ||||
|   def switches(), do: [queue_timeout: :integer, local: :boolean, timeout: :integer, | ||||
|                        table_headers: :boolean] | ||||
|   def switches(), | ||||
|     do: [queue_timeout: :integer, local: :boolean, timeout: :integer, table_headers: :boolean] | ||||
| 
 | ||||
|   def aliases(), do: [t: :timeout] | ||||
| 
 | ||||
|   defp default_opts() do | ||||
|     %{vhost: "/", local: false, queue_timeout: 15, table_headers: true} | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults([_|_] = args, opts) do | ||||
|   def merge_defaults([_ | _] = args, opts) do | ||||
|     {args, Map.merge(default_opts(), opts)} | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults([], opts) do | ||||
|     merge_defaults(~w(name), opts) | ||||
|   end | ||||
|  | @ -57,19 +58,28 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUnresponsiveQueuesCommand do | |||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run(args, %{node: node_name, vhost: vhost, timeout: timeout, | ||||
|                   queue_timeout: qtimeout, local: local_opt}) do | ||||
|   def run(args, %{ | ||||
|         node: node_name, | ||||
|         vhost: vhost, | ||||
|         timeout: timeout, | ||||
|         queue_timeout: qtimeout, | ||||
|         local: local_opt | ||||
|       }) do | ||||
|     info_keys = InfoKeys.prepare_info_keys(args) | ||||
|     queue_timeout = qtimeout * 1000 | ||||
|     Helpers.with_nodes_in_cluster(node_name, fn(nodes) -> | ||||
|       local_mfa  = {:rabbit_amqqueue, :emit_unresponsive_local, [vhost, info_keys, queue_timeout]} | ||||
|       all_mfa  = {:rabbit_amqqueue, :emit_unresponsive, [nodes, vhost, info_keys, queue_timeout]} | ||||
|       {chunks, mfas} = case local_opt do | ||||
|           true  -> {1, [local_mfa]}; | ||||
| 
 | ||||
|     Helpers.with_nodes_in_cluster(node_name, fn nodes -> | ||||
|       local_mfa = {:rabbit_amqqueue, :emit_unresponsive_local, [vhost, info_keys, queue_timeout]} | ||||
|       all_mfa = {:rabbit_amqqueue, :emit_unresponsive, [nodes, vhost, info_keys, queue_timeout]} | ||||
| 
 | ||||
|       {chunks, mfas} = | ||||
|         case local_opt do | ||||
|           true -> {1, [local_mfa]} | ||||
|           false -> {Kernel.length(nodes), [all_mfa]} | ||||
|         end | ||||
|         RpcStream.receive_list_items(node_name, mfas, timeout, info_keys, chunks) | ||||
|       end) | ||||
| 
 | ||||
|       RpcStream.receive_list_items(node_name, mfas, timeout, info_keys, chunks) | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|  | @ -77,9 +87,9 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUnresponsiveQueuesCommand do | |||
|   end | ||||
| 
 | ||||
|   def usage_additional() do | ||||
|       "<unresponsive_queueinfoitem> must be a member of the list [" <> | ||||
|     "<unresponsive_queueinfoitem> must be a member of the list [" <> | ||||
|       Enum.join(@info_keys, ", ") <> "]." | ||||
|   end | ||||
| 
 | ||||
|   def banner(_,%{vhost: vhost}), do: "Listing unresponsive queues for vhost #{vhost} ..." | ||||
|   def banner(_, %{vhost: vhost}), do: "Listing unresponsive queues for vhost #{vhost} ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListUserPermissionsCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -29,18 +28,19 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUserPermissionsCommand do | |||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([username], %{node: node_name, timeout: time_out}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|         :rabbit_auth_backend_internal, | ||||
|         :list_user_permissions, | ||||
|         [username], | ||||
|         time_out | ||||
|       ) | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :list_user_permissions, | ||||
|       [username], | ||||
|       time_out | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "list_user_permissions [--no-table-headers] <username>" | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListUserTopicPermissionsCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -29,18 +28,19 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUserTopicPermissionsCommand do | |||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([username], %{node: node_name, timeout: time_out}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|         :rabbit_auth_backend_internal, | ||||
|         :list_user_topic_permissions, | ||||
|         [username], | ||||
|         time_out | ||||
|       ) | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :list_user_topic_permissions, | ||||
|       [username], | ||||
|       time_out | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "list_user_topic_permissions [--no-table-headers] <username>" | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListUsersCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -24,13 +23,14 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListUsersCommand do | |||
|   def switches(), do: [timeout: :integer, table_headers: :boolean] | ||||
|   def aliases(), do: [t: :timeout] | ||||
| 
 | ||||
| def merge_defaults(args, opts) do | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
|  | @ -41,5 +41,5 @@ def merge_defaults(args, opts) do | |||
| 
 | ||||
|   def usage, do: "list_users [--no-table-headers]" | ||||
| 
 | ||||
|   def banner(_,_), do: "Listing users ..." | ||||
|   def banner(_, _), do: "Listing users ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostLimitsCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -25,24 +24,32 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostLimitsCommand do | |||
|   def merge_defaults(args, %{global: true} = opts) do | ||||
|     {args, Map.merge(%{table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{vhost: "/", table_headers: true}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _) do | ||||
|   def validate([_ | _], _) do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, global: true}) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_vhost_limit, :list, []) do | ||||
|       []              -> [] | ||||
|       {:error, err}   -> {:error, err} | ||||
|       {:badrpc, node} -> {:badrpc, node} | ||||
|       val             -> | ||||
|         Enum.map(val, fn({vhost, val}) -> | ||||
|       [] -> | ||||
|         [] | ||||
| 
 | ||||
|       {:error, err} -> | ||||
|         {:error, err} | ||||
| 
 | ||||
|       {:badrpc, node} -> | ||||
|         {:badrpc, node} | ||||
| 
 | ||||
|       val -> | ||||
|         Enum.map(val, fn {vhost, val} -> | ||||
|           {:ok, val_encoded} = JSON.encode(Map.new(val)) | ||||
|           [vhost: vhost, limits: val_encoded] | ||||
|         end) | ||||
|  | @ -51,10 +58,16 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostLimitsCommand do | |||
| 
 | ||||
|   def run([], %{node: node_name, vhost: vhost}) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_vhost_limit, :list, [vhost]) do | ||||
|       []              -> [] | ||||
|       {:error, err}   -> {:error, err} | ||||
|       {:badrpc, node} -> {:badrpc, node} | ||||
|       val when is_list(val) or is_map(val)  -> | ||||
|       [] -> | ||||
|         [] | ||||
| 
 | ||||
|       {:error, err} -> | ||||
|         {:error, err} | ||||
| 
 | ||||
|       {:badrpc, node} -> | ||||
|         {:badrpc, node} | ||||
| 
 | ||||
|       val when is_list(val) or is_map(val) -> | ||||
|         JSON.encode(Map.new(val)) | ||||
|     end | ||||
|   end | ||||
|  | @ -64,6 +77,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostLimitsCommand do | |||
|   def banner([], %{global: true}) do | ||||
|     "Listing limits for all vhosts ..." | ||||
|   end | ||||
| 
 | ||||
|   def banner([], %{vhost: vhost}) do | ||||
|     "Listing limits for vhost \"#{vhost}\" ..." | ||||
|   end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostsCommand do | ||||
|   alias RabbitMQ.CLI.Ctl.InfoKeys | ||||
| 
 | ||||
|  | @ -33,6 +32,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostsCommand do | |||
|   def merge_defaults([], opts) do | ||||
|     merge_defaults(["name"], opts) | ||||
|   end | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     {args, Map.merge(%{table_headers: true}, opts)} | ||||
|   end | ||||
|  | @ -46,7 +46,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostsCommand do | |||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([_|_] = args, %{node: node_name, timeout: time_out}) do | ||||
|   def run([_ | _] = args, %{node: node_name, timeout: time_out}) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_vhost, :info_all, [], time_out) | ||||
|     |> filter_by_arg(args) | ||||
|   end | ||||
|  | @ -61,17 +61,16 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ListVhostsCommand do | |||
|     vhosts | ||||
|   end | ||||
| 
 | ||||
|   defp filter_by_arg(vhosts, [_|_] = args) do | ||||
|   defp filter_by_arg(vhosts, [_ | _] = args) do | ||||
|     symbol_args = InfoKeys.prepare_info_keys(args) | ||||
| 
 | ||||
|     vhosts | ||||
|     |> Enum.map( | ||||
|       fn(vhost) -> | ||||
|         symbol_args | ||||
|         |> Enum.filter(fn(arg) -> vhost[arg] != nil end) | ||||
|         |> Enum.map(fn(arg) -> {arg, vhost[arg]} end) | ||||
|       end | ||||
|     ) | ||||
|     |> Enum.map(fn vhost -> | ||||
|       symbol_args | ||||
|       |> Enum.filter(fn arg -> vhost[arg] != nil end) | ||||
|       |> Enum.map(fn arg -> {arg, vhost[arg]} end) | ||||
|     end) | ||||
|   end | ||||
| 
 | ||||
|   def banner(_,_), do: "Listing vhosts ..." | ||||
|   def banner(_, _), do: "Listing vhosts ..." | ||||
| end | ||||
|  |  | |||
|  | @ -23,11 +23,13 @@ defmodule RabbitMQ.CLI.Ctl.Commands.NodeHealthCheckCommand do | |||
|   def aliases(), do: [t: :timeout] | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     timeout = case opts[:timeout] do | ||||
|       nil       -> @default_timeout; | ||||
|       :infinity -> @default_timeout; | ||||
|       other     -> other | ||||
|     end | ||||
|     timeout = | ||||
|       case opts[:timeout] do | ||||
|         nil -> @default_timeout | ||||
|         :infinity -> @default_timeout | ||||
|         other -> other | ||||
|       end | ||||
| 
 | ||||
|     {args, Map.merge(opts, %{timeout: timeout})} | ||||
|   end | ||||
| 
 | ||||
|  | @ -38,17 +40,22 @@ defmodule RabbitMQ.CLI.Ctl.Commands.NodeHealthCheckCommand do | |||
| 
 | ||||
|   def run([], %{node: node_name, timeout: timeout}) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_health_check, :node, [node_name, timeout]) do | ||||
|       :ok                                      -> | ||||
|       :ok -> | ||||
|         :ok | ||||
|       true                                     -> | ||||
| 
 | ||||
|       true -> | ||||
|         :ok | ||||
|       {:badrpc, _} = err                       -> | ||||
| 
 | ||||
|       {:badrpc, _} = err -> | ||||
|         err | ||||
|       {:error_string, error_message}           -> | ||||
| 
 | ||||
|       {:error_string, error_message} -> | ||||
|         {:healthcheck_failed, error_message} | ||||
| 
 | ||||
|       {:node_is_ko, error_message, _exit_code} -> | ||||
|         {:healthcheck_failed, error_message} | ||||
|       other                                    -> | ||||
| 
 | ||||
|       other -> | ||||
|         other | ||||
|     end | ||||
|   end | ||||
|  | @ -56,16 +63,17 @@ defmodule RabbitMQ.CLI.Ctl.Commands.NodeHealthCheckCommand do | |||
|   def output(:ok, _) do | ||||
|     {:ok, "Health check passed"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:healthcheck_failed, message}, _) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      "Error: healthcheck failed. Message: #{message}"} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def usage, do: "node_health_check" | ||||
| 
 | ||||
|   def banner(_, %{node: node_name, timeout: timeout}) do | ||||
|     ["Timeout: #{trunc(timeout / 1000)} seconds ...", | ||||
|      "Checking health of node #{node_name} ..."] | ||||
|     ["Timeout: #{trunc(timeout / 1000)} seconds ...", "Checking health of node #{node_name} ..."] | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is Pivotal Software, Inc. | ||||
| ## Copyright (c) 2016-2018 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.PingCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
| 
 | ||||
|  | @ -22,11 +21,13 @@ defmodule RabbitMQ.CLI.Ctl.Commands.PingCommand do | |||
|   def scopes(), do: [:ctl, :diagnostics] | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     timeout = case opts[:timeout] do | ||||
|       nil       -> @default_timeout; | ||||
|       :infinity -> @default_timeout; | ||||
|       other     -> other | ||||
|     end | ||||
|     timeout = | ||||
|       case opts[:timeout] do | ||||
|         nil -> @default_timeout | ||||
|         :infinity -> @default_timeout | ||||
|         other -> other | ||||
|       end | ||||
| 
 | ||||
|     {args, Map.merge(opts, %{timeout: timeout})} | ||||
|   end | ||||
| 
 | ||||
|  | @ -40,20 +41,27 @@ defmodule RabbitMQ.CLI.Ctl.Commands.PingCommand do | |||
|     # this is very similar to what net_adm:ping/1 does reimplemented with support for custom timeouts | ||||
|     # and error values that are used by CLI commands | ||||
|     msg = "Failed to connect and authenticate to #{node_name} in #{timeout} ms" | ||||
| 
 | ||||
|     try do | ||||
|       case :gen.call({:net_kernel, node_name}, :'$gen_call', {:is_auth, node()}, timeout) do | ||||
|         :ok      -> :ok | ||||
|         {:ok, _} -> :ok | ||||
|         _        -> | ||||
|       case :gen.call({:net_kernel, node_name}, :"$gen_call", {:is_auth, node()}, timeout) do | ||||
|         :ok -> | ||||
|           :ok | ||||
| 
 | ||||
|         {:ok, _} -> | ||||
|           :ok | ||||
| 
 | ||||
|         _ -> | ||||
|           :erlang.disconnect_node(node_name) | ||||
|           {:error, msg} | ||||
|       end | ||||
|     catch :exit, _ -> | ||||
|             :erlang.disconnect_node(node_name) | ||||
|             {:error, msg} | ||||
|           _ -> | ||||
|             :erlang.disconnect_node(node_name) | ||||
|             {:error, msg} | ||||
|     catch | ||||
|       :exit, _ -> | ||||
|         :erlang.disconnect_node(node_name) | ||||
|         {:error, msg} | ||||
| 
 | ||||
|       _ -> | ||||
|         :erlang.disconnect_node(node_name) | ||||
|         {:error, msg} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -62,8 +70,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.PingCommand do | |||
|   end | ||||
| 
 | ||||
|   def banner([], %{node: node_name, timeout: timeout}) when is_number(timeout) do | ||||
|     "Will ping #{node_name}. This only checks if the OS process is running and registered with epmd. Timeout: #{timeout} ms." | ||||
|     "Will ping #{node_name}. This only checks if the OS process is running and registered with epmd. Timeout: #{ | ||||
|       timeout | ||||
|     } ms." | ||||
|   end | ||||
| 
 | ||||
|   def banner([], %{node: node_name, timeout: _timeout}) do | ||||
|     "Will ping #{node_name}. This only checks if the OS process is running and registered with epmd." | ||||
|   end | ||||
|  | @ -71,9 +82,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.PingCommand do | |||
|   def output(:ok, _) do | ||||
|     {:ok, "Ping succeeded"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :timeout}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      "Error: timed out while waiting for a response from #{node_name}."} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.PurgeQueueCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -38,20 +37,27 @@ defmodule RabbitMQ.CLI.Ctl.Commands.PurgeQueueCommand do | |||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([queue], %{node: node_name, vhost: vhost, timeout: timeout}) do | ||||
|     res = :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_amqqueue, :lookup, [:rabbit_misc.r(vhost, :queue, queue)], timeout) | ||||
|     res = | ||||
|       :rabbit_misc.rpc_call( | ||||
|         node_name, | ||||
|         :rabbit_amqqueue, | ||||
|         :lookup, | ||||
|         [:rabbit_misc.r(vhost, :queue, queue)], | ||||
|         timeout | ||||
|       ) | ||||
| 
 | ||||
|     case res do | ||||
|       {:ok, q} -> purge(node_name, q, timeout) | ||||
|       _        -> res | ||||
|       _ -> res | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   defp purge(node_name, q, timeout) do | ||||
|     res = :rabbit_misc.rpc_call(node_name, :rabbit_amqqueue, :purge, [q], timeout) | ||||
| 
 | ||||
|     case res do | ||||
|       {:ok, _message_count} -> :ok | ||||
|       _                     -> res | ||||
|       _ -> res | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,9 +13,7 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.QuorumStatusCommand do | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|  | @ -29,10 +27,12 @@ defmodule RabbitMQ.CLI.Ctl.Commands.QuorumStatusCommand do | |||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, Map.merge(default_opts(), opts)} | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 1 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 1 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_], _), do: :ok | ||||
| 
 | ||||
|   def validate([], _) do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|  | @ -42,7 +42,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.QuorumStatusCommand do | |||
|   def run([name] = _args, %{node: node_name, vhost: vhost}) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_quorum_queue, :status, [vhost, name]) do | ||||
|       {:error, :classic_queue_not_supported} -> | ||||
|         {:error, "Cannot get quorum status of a classic queue"}; | ||||
|         {:error, "Cannot get quorum status of a classic queue"} | ||||
| 
 | ||||
|       other -> | ||||
|         other | ||||
|     end | ||||
|  | @ -52,5 +53,6 @@ defmodule RabbitMQ.CLI.Ctl.Commands.QuorumStatusCommand do | |||
|     "quorum_status [-p <vhost>] <queuename>" | ||||
|   end | ||||
| 
 | ||||
|   def banner([name], %{node: node_name}), do: "Status of quorum queue #{name} on node #{node_name} ..." | ||||
|   def banner([name], %{node: node_name}), | ||||
|     do: "Status of quorum queue #{name} on node #{node_name} ..." | ||||
| end | ||||
|  |  | |||
|  | @ -24,36 +24,44 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RenameClusterNodeCommand do | |||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_], _), do: {:validation_failure, :not_enough_args} | ||||
| 
 | ||||
|   def validate(_, _) do | ||||
|     :ok | ||||
|   end | ||||
| 
 | ||||
|   def validate_execution_environment(args, opts) do | ||||
|     Validators.chain([&validate_args_count_even/2, | ||||
|                       &Validators.node_is_not_running/2, | ||||
|                       &Validators.mnesia_dir_is_set/2, | ||||
|                       &Validators.rabbit_is_loaded/2], | ||||
|                      [args, opts]) | ||||
|     Validators.chain( | ||||
|       [ | ||||
|         &validate_args_count_even/2, | ||||
|         &Validators.node_is_not_running/2, | ||||
|         &Validators.mnesia_dir_is_set/2, | ||||
|         &Validators.rabbit_is_loaded/2 | ||||
|       ], | ||||
|       [args, opts] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def run(nodes, %{node: node_name}) do | ||||
|     node_pairs = make_node_pairs(nodes) | ||||
| 
 | ||||
|     try do | ||||
|       :rabbit_mnesia_rename.rename(node_name, node_pairs) | ||||
|     catch _, reason -> | ||||
|       {:rename_failed, reason} | ||||
|     catch | ||||
|       _, reason -> | ||||
|         {:rename_failed, reason} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
| 
 | ||||
|   defp validate_args_count_even(args, _) do | ||||
|     case agrs_count_even?(args) do | ||||
|       true  -> :ok; | ||||
|       true -> | ||||
|         :ok | ||||
| 
 | ||||
|       false -> | ||||
|         {:validation_failure, | ||||
|           {:bad_argument, "Argument list should contain even number of nodes"}} | ||||
|          {:bad_argument, "Argument list should contain even number of nodes"}} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -64,6 +72,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RenameClusterNodeCommand do | |||
|   defp make_node_pairs([]) do | ||||
|     [] | ||||
|   end | ||||
| 
 | ||||
|   defp make_node_pairs([from, to | rest]) do | ||||
|     [{to_atom(from), to_atom(to)} | make_node_pairs(rest)] | ||||
|   end | ||||
|  | @ -73,9 +82,13 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RenameClusterNodeCommand do | |||
|   end | ||||
| 
 | ||||
|   def banner(args, _) do | ||||
|     ["Renaming cluster nodes: \n ", | ||||
|      for {node_from, node_to} <- make_node_pairs(args) do "#{node_from} -> #{node_to} \n" end] | ||||
|     |> List.flatten | ||||
|     |> Enum.join | ||||
|     [ | ||||
|       "Renaming cluster nodes: \n ", | ||||
|       for {node_from, node_to} <- make_node_pairs(args) do | ||||
|         "#{node_from} -> #{node_to} \n" | ||||
|       end | ||||
|     ] | ||||
|     |> List.flatten() | ||||
|     |> Enum.join() | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,12 +13,21 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ReportCommand do | ||||
|   alias RabbitMQ.CLI.Ctl.Commands.{ClusterStatusCommand, EnvironmentCommand, | ||||
|     ListBindingsCommand, ListChannelsCommand, ListConnectionsCommand, | ||||
|     ListExchangesCommand, ListGlobalParametersCommand, ListParametersCommand, | ||||
|     ListPermissionsCommand, ListPoliciesCommand, ListQueuesCommand, StatusCommand} | ||||
|   alias RabbitMQ.CLI.Ctl.Commands.{ | ||||
|     ClusterStatusCommand, | ||||
|     EnvironmentCommand, | ||||
|     ListBindingsCommand, | ||||
|     ListChannelsCommand, | ||||
|     ListConnectionsCommand, | ||||
|     ListExchangesCommand, | ||||
|     ListGlobalParametersCommand, | ||||
|     ListParametersCommand, | ||||
|     ListPermissionsCommand, | ||||
|     ListPoliciesCommand, | ||||
|     ListQueuesCommand, | ||||
|     StatusCommand | ||||
|   } | ||||
| 
 | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -29,13 +38,16 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ReportCommand do | |||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) != 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) != 0, | ||||
|     do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   def validate([], %{formatter: formatter}) do | ||||
|     case formatter do | ||||
|       "report" -> :ok | ||||
|       _other   -> {:validation_failure, "Only report formatter is supported"} | ||||
|       _other -> {:validation_failure, "Only report formatter is supported"} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
|  | @ -44,26 +56,32 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ReportCommand do | |||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_vhost, :list, []) do | ||||
|       {:badrpc, _} = err -> | ||||
|         err | ||||
| 
 | ||||
|       vhosts -> | ||||
|         data = | ||||
|           [run_command(StatusCommand, [], opts), | ||||
|            run_command(ClusterStatusCommand, [], opts), | ||||
|            run_command(EnvironmentCommand, [], opts), | ||||
|            run_command(ListConnectionsCommand, info_keys(ListConnectionsCommand), opts), | ||||
|            run_command(ListChannelsCommand, info_keys(ListChannelsCommand), opts)] | ||||
|         data = [ | ||||
|           run_command(StatusCommand, [], opts), | ||||
|           run_command(ClusterStatusCommand, [], opts), | ||||
|           run_command(EnvironmentCommand, [], opts), | ||||
|           run_command(ListConnectionsCommand, info_keys(ListConnectionsCommand), opts), | ||||
|           run_command(ListChannelsCommand, info_keys(ListChannelsCommand), opts) | ||||
|         ] | ||||
| 
 | ||||
|         vhost_data = | ||||
|             vhosts | ||||
|             |> Enum.flat_map(fn v -> | ||||
|               opts = Map.put(opts, :vhost, v) | ||||
|               [run_command(ListQueuesCommand, info_keys(ListQueuesCommand), opts), | ||||
|                run_command(ListExchangesCommand, info_keys(ListExchangesCommand), opts), | ||||
|                run_command(ListBindingsCommand, info_keys(ListBindingsCommand), opts), | ||||
|                run_command(ListPermissionsCommand, [], opts), | ||||
|                run_command(ListPoliciesCommand, [], opts), | ||||
|                run_command(ListGlobalParametersCommand, [], opts), | ||||
|                run_command(ListParametersCommand, [], opts)] | ||||
|             end) | ||||
|           vhosts | ||||
|           |> Enum.flat_map(fn v -> | ||||
|             opts = Map.put(opts, :vhost, v) | ||||
| 
 | ||||
|             [ | ||||
|               run_command(ListQueuesCommand, info_keys(ListQueuesCommand), opts), | ||||
|               run_command(ListExchangesCommand, info_keys(ListExchangesCommand), opts), | ||||
|               run_command(ListBindingsCommand, info_keys(ListBindingsCommand), opts), | ||||
|               run_command(ListPermissionsCommand, [], opts), | ||||
|               run_command(ListPoliciesCommand, [], opts), | ||||
|               run_command(ListGlobalParametersCommand, [], opts), | ||||
|               run_command(ListParametersCommand, [], opts) | ||||
|             ] | ||||
|           end) | ||||
| 
 | ||||
|         data ++ vhost_data | ||||
|     end | ||||
|   end | ||||
|  | @ -75,7 +93,6 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ReportCommand do | |||
|     {command, banner, command_result} | ||||
|   end | ||||
| 
 | ||||
| 
 | ||||
|   defp info_keys(command) do | ||||
|     command.info_keys() | ||||
|     |> Enum.map(&Atom.to_string/1) | ||||
|  | @ -83,5 +100,5 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ReportCommand do | |||
| 
 | ||||
|   def usage, do: "report" | ||||
| 
 | ||||
|   def banner(_,%{node: node_name}), do: "Reporting server status of node #{node_name} ..." | ||||
|   def banner(_, %{node: node_name}), do: "Reporting server status of node #{node_name} ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,30 +13,28 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ResetCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppStopped | ||||
|    | ||||
| 
 | ||||
|   def run([], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_mnesia, :reset, []) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "reset" | ||||
| 
 | ||||
| 
 | ||||
|   def banner(_, %{node: node_name}), do: "Resetting node #{node_name} ..." | ||||
| 
 | ||||
| 
 | ||||
|   def output({:error, :mnesia_unexpectedly_running}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      RabbitMQ.CLI.DefaultOutput.mnesia_running_error(node_name)} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -23,8 +23,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RestartVhostCommand do | |||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, Map.merge(%{vhost: "/"}, opts)} | ||||
| 
 | ||||
|   def validate([], _),  do: :ok | ||||
|   def validate(_, _),   do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: :ok | ||||
|   def validate(_, _), do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|  | @ -34,20 +34,22 @@ defmodule RabbitMQ.CLI.Ctl.Commands.RestartVhostCommand do | |||
| 
 | ||||
|   def usage, do: "restart_vhost [-p <vhost>]" | ||||
| 
 | ||||
|   def banner(_,%{node: node_name, vhost: vhost}) do | ||||
|   def banner(_, %{node: node_name, vhost: vhost}) do | ||||
|     "Trying to restart vhost '#{vhost}' on node '#{node_name}' ..." | ||||
|   end | ||||
| 
 | ||||
|   def output({:ok, _pid}, %{vhost: vhost, node: node_name}) do | ||||
|     {:ok, "Successfully restarted vhost '#{vhost}' on node '#{node_name}'"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, {:already_started, _pid}}, %{vhost: vhost, node: node_name}) do | ||||
|     {:ok, "Vhost '#{vhost}' is already running on node '#{node_name}'"} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, err}, %{vhost: vhost, node: node_name}) do | ||||
|     {:error, ExitCodes.exit_software(), | ||||
|      ["Failed to start vhost '#{vhost}' on node '#{node_name}'", | ||||
|       "Reason: #{inspect(err)}"]} | ||||
|      ["Failed to start vhost '#{vhost}' on node '#{node_name}'", "Reason: #{inspect(err)}"]} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -13,14 +13,13 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.RotateLogsCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetClusterNameCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -35,8 +34,10 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetClusterNameCommand do | |||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([cluster_name], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|       :rabbit_nodes, :set_cluster_name, [cluster_name, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_nodes, :set_cluster_name, [ | ||||
|       cluster_name, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def banner([cluster_name], _) do | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -35,13 +34,17 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand do | |||
| 
 | ||||
|   def validate([limit], _) do | ||||
|     case Integer.parse(limit) do | ||||
|       {_, ""} -> :ok | ||||
|       {_, ""} -> | ||||
|         :ok | ||||
| 
 | ||||
|       {limit_val, units} -> | ||||
|         case Helpers.memory_unit_absolute(limit_val, units) do | ||||
|           scaled_limit when is_integer(scaled_limit) -> :ok | ||||
|           _ -> {:validation_failure, :bad_argument} | ||||
|         end | ||||
|       _ -> {:validation_failure,  :bad_argument} | ||||
| 
 | ||||
|       _ -> | ||||
|         {:validation_failure, :bad_argument} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -52,7 +55,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|rest], _) when length(rest) > 0 do | ||||
|   def validate([_ | rest], _) when length(rest) > 0 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|  | @ -62,11 +65,10 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand do | |||
|     set_disk_free_limit_relative(args, opts) | ||||
|   end | ||||
| 
 | ||||
| 
 | ||||
|   def run([limit], %{node: _} = opts) when is_binary(limit) do | ||||
|     case Integer.parse(limit) do | ||||
|       {limit_val, ""}     -> set_disk_free_limit_absolute([limit_val], opts) | ||||
|       {limit_val, units}  -> set_disk_free_limit_in_units([limit_val, units], opts) | ||||
|       {limit_val, ""} -> set_disk_free_limit_absolute([limit_val], opts) | ||||
|       {limit_val, units} -> set_disk_free_limit_in_units([limit_val, units], opts) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -77,17 +79,17 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand do | |||
|   ## ----------------------- Memory-Relative Call ---------------------------- | ||||
| 
 | ||||
|   defp set_disk_free_limit_relative(["mem_relative", fraction], %{node: node_name}) | ||||
|       when is_float(fraction) do | ||||
|        when is_float(fraction) do | ||||
|     make_rpc_call(node_name, [{:mem_relative, fraction}]) | ||||
|   end | ||||
| 
 | ||||
|   defp set_disk_free_limit_relative(["mem_relative", integer_input], %{node: node_name}) | ||||
|       when is_integer(integer_input) do | ||||
|        when is_integer(integer_input) do | ||||
|     make_rpc_call(node_name, [{:mem_relative, integer_input * 1.0}]) | ||||
|   end | ||||
| 
 | ||||
|   defp set_disk_free_limit_relative(["mem_relative", fraction_str], %{node: _} = opts) | ||||
|       when is_binary(fraction_str) do | ||||
|        when is_binary(fraction_str) do | ||||
|     {fraction_val, ""} = Float.parse(fraction_str) | ||||
|     set_disk_free_limit_relative(["mem_relative", fraction_val], opts) | ||||
|   end | ||||
|  | @ -99,7 +101,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand do | |||
|   end | ||||
| 
 | ||||
|   defp set_disk_free_limit_absolute([limit], %{node: _} = opts) when is_float(limit) do | ||||
|     set_disk_free_limit_absolute([limit |> Float.floor |> round], opts) | ||||
|     set_disk_free_limit_absolute([limit |> Float.floor() |> round], opts) | ||||
|   end | ||||
| 
 | ||||
|   defp set_disk_free_limit_in_units([limit_val, units], opts) do | ||||
|  | @ -119,8 +121,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetDiskFreeLimitCommand do | |||
|     "Setting disk free limit on #{node_name} to #{arg} times the total RAM ..." | ||||
|   end | ||||
| 
 | ||||
|   def banner([arg], %{node: node_name}), do: "Setting disk free limit on #{node_name} to #{arg} bytes ..." | ||||
| 
 | ||||
|   def banner([arg], %{node: node_name}), | ||||
|     do: "Setting disk free limit on #{node_name} to #{arg} bytes ..." | ||||
| 
 | ||||
|   def usage, do: "set_disk_free_limit <disk_limit>\nset_disk_free_limit mem_relative <fraction>" | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetGlobalParameterCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -28,11 +27,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetGlobalParameterCommand do | |||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) < 2 do | ||||
|   def validate([_ | _] = args, _) when length(args) < 2 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 2 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 2 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|  | @ -41,7 +40,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetGlobalParameterCommand do | |||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([name, value], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_runtime_parameters, | ||||
|       :parse_set_global, | ||||
|       [name, value, Helpers.cli_acting_user()] | ||||
|  |  | |||
|  | @ -15,16 +15,30 @@ | |||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetLogLevelCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   @known_levels ["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency", "none"] | ||||
|   @known_levels [ | ||||
|     "debug", | ||||
|     "info", | ||||
|     "notice", | ||||
|     "warning", | ||||
|     "error", | ||||
|     "critical", | ||||
|     "alert", | ||||
|     "emergency", | ||||
|     "none" | ||||
|   ] | ||||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   def validate([level], _) do | ||||
|     case Enum.member?(@known_levels, level) do | ||||
|       true  -> :ok | ||||
|       false -> {:error, "level #{level} is not supported. Try one of debug, info, warning, error, none"} | ||||
|       true -> | ||||
|         :ok | ||||
| 
 | ||||
|       false -> | ||||
|         {:error, "level #{level} is not supported. Try one of debug, info, warning, error, none"} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -40,8 +54,9 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetLogLevelCommand do | |||
|   def banner([log_level], _), do: "Setting log level to \"#{log_level}\" ..." | ||||
| 
 | ||||
|   def output({:error, {:invalid_log_level, level}}, _opts) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      "level #{level} is not supported. Try one of debug, info, warning, error, none"} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetOperatorPolicyCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -30,11 +29,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetOperatorPolicyCommand do | |||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) < 3 do | ||||
|   def validate([_ | _] = args, _) when length(args) < 3 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 3 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 3 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|  | @ -42,25 +41,27 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetOperatorPolicyCommand do | |||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([name, pattern, definition], %{node: node_name, | ||||
|                                          vhost: vhost, | ||||
|                                          priority: priority, | ||||
|                                          apply_to: apply_to}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|   def run([name, pattern, definition], %{ | ||||
|         node: node_name, | ||||
|         vhost: vhost, | ||||
|         priority: priority, | ||||
|         apply_to: apply_to | ||||
|       }) do | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_policy, | ||||
|       :parse_set_op, | ||||
|       [vhost, | ||||
|        name, | ||||
|        pattern, | ||||
|        definition, | ||||
|        priority, | ||||
|        apply_to, | ||||
|        Helpers.cli_acting_user()]) | ||||
|       [vhost, name, pattern, definition, priority, apply_to, Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "set_operator_policy [-p <vhost>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>" | ||||
|   def usage, | ||||
|     do: | ||||
|       "set_operator_policy [-p <vhost>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>" | ||||
| 
 | ||||
|   def banner([name, pattern, definition], %{vhost: vhost, priority: priority}) do | ||||
|     "Setting operator policy override \"#{name}\" for pattern \"#{pattern}\" to \"#{definition}\" with priority \"#{priority}\" for vhost \"#{vhost}\" ..." | ||||
|     "Setting operator policy override \"#{name}\" for pattern \"#{pattern}\" to \"#{definition}\" with priority \"#{ | ||||
|       priority | ||||
|     }\" for vhost \"#{vhost}\" ..." | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetParameterCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -28,11 +27,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetParameterCommand do | |||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) < 3 do | ||||
|   def validate([_ | _] = args, _) when length(args) < 3 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 3 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 3 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|  | @ -41,7 +40,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetParameterCommand do | |||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([component_name, name, value], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_runtime_parameters, | ||||
|       :parse_set, | ||||
|       [vhost, component_name, name, value, Helpers.cli_acting_user()] | ||||
|  | @ -51,6 +51,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetParameterCommand do | |||
|   def usage, do: "set_parameter [-p <vhost>] <component_name> <name> <value>" | ||||
| 
 | ||||
|   def banner([component_name, name, value], %{vhost: vhost}) do | ||||
|     "Setting runtime parameter \"#{component_name}\" for component \"#{name}\" to \"#{value}\" in vhost \"#{vhost}\" ..." | ||||
|     "Setting runtime parameter \"#{component_name}\" for component \"#{name}\" to \"#{value}\" in vhost \"#{ | ||||
|       vhost | ||||
|     }\" ..." | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetPermissionsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -28,19 +27,21 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetPermissionsCommand do | |||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) < 4 do | ||||
|   def validate([_ | _] = args, _) when length(args) < 4 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 4 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 4 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([user, conf, write, read], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :set_permissions, | ||||
|       [user, vhost, conf, write, read, Helpers.cli_acting_user()] | ||||
|  | @ -49,5 +50,6 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetPermissionsCommand do | |||
| 
 | ||||
|   def usage, do: "set_permissions [-p <vhost>] <username> <conf> <write> <read>" | ||||
| 
 | ||||
|   def banner([user|_], %{vhost: vhost}), do: "Setting permissions for user \"#{user}\" in vhost \"#{vhost}\" ..." | ||||
|   def banner([user | _], %{vhost: vhost}), | ||||
|     do: "Setting permissions for user \"#{user}\" in vhost \"#{vhost}\" ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetPolicyCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -30,11 +29,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetPolicyCommand do | |||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) < 3 do | ||||
|   def validate([_ | _] = args, _) when length(args) < 3 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 3 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 3 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|  | @ -42,25 +41,27 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetPolicyCommand do | |||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([name, pattern, definition], %{node: node_name, | ||||
|                                          vhost: vhost, | ||||
|                                          priority: priority, | ||||
|                                          apply_to: apply_to}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|   def run([name, pattern, definition], %{ | ||||
|         node: node_name, | ||||
|         vhost: vhost, | ||||
|         priority: priority, | ||||
|         apply_to: apply_to | ||||
|       }) do | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_policy, | ||||
|       :parse_set, | ||||
|       [vhost, | ||||
|        name, | ||||
|        pattern, | ||||
|        definition, | ||||
|        priority, | ||||
|        apply_to, | ||||
|        Helpers.cli_acting_user()]) | ||||
|       [vhost, name, pattern, definition, priority, apply_to, Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "set_policy [-p <vhost>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>" | ||||
|   def usage, | ||||
|     do: | ||||
|       "set_policy [-p <vhost>] [--priority <priority>] [--apply-to <apply-to>] <name> <pattern> <definition>" | ||||
| 
 | ||||
|   def banner([name, pattern, definition], %{vhost: vhost, priority: priority}) do | ||||
|     "Setting policy \"#{name}\" for pattern \"#{pattern}\" to \"#{definition}\" with priority \"#{priority}\" for vhost \"#{vhost}\" ..." | ||||
|     "Setting policy \"#{name}\" for pattern \"#{pattern}\" to \"#{definition}\" with priority \"#{ | ||||
|       priority | ||||
|     }\" for vhost \"#{vhost}\" ..." | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetTopicPermissionsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -27,26 +26,32 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetTopicPermissionsCommand do | |||
|   def validate([], _) do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
|   def validate([_|_] = args, _) when length(args) < 4 do | ||||
| 
 | ||||
|   def validate([_ | _] = args, _) when length(args) < 4 do | ||||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 4 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 4 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([user, exchange, write_pattern, read_pattern], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :set_topic_permissions, | ||||
|       [user, vhost, exchange, write_pattern, read_pattern, Helpers.cli_acting_user()] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "set_topic_permissions [-p <vhost>] <username> <exchange> <write_pattern> <read_pattern>" | ||||
|   def usage, | ||||
|     do: "set_topic_permissions [-p <vhost>] <username> <exchange> <write_pattern> <read_pattern>" | ||||
| 
 | ||||
|   def banner([user, exchange, _, _], %{vhost: vhost}), do: "Setting topic permissions on \"#{exchange}\" for user \"#{user}\" in vhost \"#{vhost}\" ..." | ||||
|   def banner([user, exchange, _, _], %{vhost: vhost}), | ||||
|     do: | ||||
|       "Setting topic permissions on \"#{exchange}\" for user \"#{user}\" in vhost \"#{vhost}\" ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetUserTagsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -28,7 +27,8 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetUserTagsCommand do | |||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([user | tags], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_auth_backend_internal, | ||||
|       :set_tags, | ||||
|       [user, tags, Helpers.cli_acting_user()] | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetVhostLimitsCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -28,7 +27,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetVhostLimitsCommand do | |||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 1 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 1 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|  | @ -37,8 +36,11 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetVhostLimitsCommand do | |||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([definition], %{node: node_name, vhost: vhost}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|                           :rabbit_vhost_limit, :parse_set, [vhost, definition, Helpers.cli_acting_user()]) | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit_vhost_limit, :parse_set, [ | ||||
|       vhost, | ||||
|       definition, | ||||
|       Helpers.cli_acting_user() | ||||
|     ]) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "set_vhost_limits [-p <vhost>] <definition>" | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.SetVmMemoryHighWatermarkCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -30,54 +29,70 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetVmMemoryHighWatermarkCommand do | |||
|     {:validation_failure, :not_enough_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(["absolute"|_] = args, _) when length(args) > 2 do | ||||
|   def validate(["absolute" | _] = args, _) when length(args) > 2 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate(["absolute", arg], _) do | ||||
|     case Integer.parse(arg) do | ||||
|       :error        ->  {:validation_failure, :bad_argument} | ||||
|       :error -> | ||||
|         {:validation_failure, :bad_argument} | ||||
| 
 | ||||
|       {_, rest} -> | ||||
|         case Enum.member?(Helpers.memory_units, rest) do | ||||
|           true -> :ok | ||||
|           false -> case Float.parse(arg) do | ||||
|                      {_, orest} when orest == rest -> | ||||
|                        {:validation_failure, {:bad_argument, "Invalid units."}} | ||||
|                      _ -> | ||||
|                        {:validation_failure, {:bad_argument, "The threshold should be an integer."}} | ||||
|                    end | ||||
|         case Enum.member?(Helpers.memory_units(), rest) do | ||||
|           true -> | ||||
|             :ok | ||||
| 
 | ||||
|           false -> | ||||
|             case Float.parse(arg) do | ||||
|               {_, orest} when orest == rest -> | ||||
|                 {:validation_failure, {:bad_argument, "Invalid units."}} | ||||
| 
 | ||||
|               _ -> | ||||
|                 {:validation_failure, {:bad_argument, "The threshold should be an integer."}} | ||||
|             end | ||||
|         end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 1 do | ||||
|   def validate([_ | _] = args, _) when length(args) > 1 do | ||||
|     {:validation_failure, :too_many_args} | ||||
|   end | ||||
| 
 | ||||
|   def validate([arg], _) when is_number(arg) and (arg < 0.0 or arg > 1.0) do | ||||
|     {:validation_failure, {:bad_argument, "The threshold should be a fraction between 0.0 and 1.0"}} | ||||
|     {:validation_failure, | ||||
|      {:bad_argument, "The threshold should be a fraction between 0.0 and 1.0"}} | ||||
|   end | ||||
| 
 | ||||
|   def validate([arg], %{}) when is_binary(arg) do | ||||
|     case Float.parse(arg) do | ||||
|       {arg, ""} when is_number(arg) and (arg < 0.0 or arg > 1.0) -> | ||||
|                {:validation_failure, {:bad_argument, "The threshold should be a fraction between 0.0 and 1.0"}} | ||||
|       {_, ""}   ->  :ok | ||||
|       _           ->  {:validation_failure, :bad_argument} | ||||
|         {:validation_failure, | ||||
|          {:bad_argument, "The threshold should be a fraction between 0.0 and 1.0"}} | ||||
| 
 | ||||
|       {_, ""} -> | ||||
|         :ok | ||||
| 
 | ||||
|       _ -> | ||||
|         {:validation_failure, :bad_argument} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run(["absolute", arg], opts) do | ||||
|     case Integer.parse(arg) do | ||||
|       {num, rest}   ->  valid_units = rest in Helpers.memory_units | ||||
|                         set_vm_memory_high_watermark_absolute({num, rest}, valid_units, opts) | ||||
|       {num, rest} -> | ||||
|         valid_units = rest in Helpers.memory_units() | ||||
|         set_vm_memory_high_watermark_absolute({num, rest}, valid_units, opts) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def run([arg], %{node: node_name}) when is_number(arg) and arg >= 0.0 do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :vm_memory_monitor, | ||||
|       :set_vm_memory_high_watermark, | ||||
|       [arg] | ||||
|  | @ -86,20 +101,31 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SetVmMemoryHighWatermarkCommand do | |||
| 
 | ||||
|   def run([arg], %{} = opts) when is_binary(arg) do | ||||
|     case Float.parse(arg) do | ||||
|       {num, ""}   ->  run([num], opts) | ||||
|       {num, ""} -> run([num], opts) | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   defp set_vm_memory_high_watermark_absolute({num, rest}, true, %{node: node_name}) when num > 0 do | ||||
|       val = Helpers.memory_unit_absolute(num, rest) | ||||
|       :rabbit_misc.rpc_call(node_name, | ||||
|         :vm_memory_monitor, | ||||
|         :set_vm_memory_high_watermark, | ||||
|         [{:absolute, val}]) | ||||
|   defp set_vm_memory_high_watermark_absolute({num, rest}, true, %{node: node_name}) | ||||
|        when num > 0 do | ||||
|     val = Helpers.memory_unit_absolute(num, rest) | ||||
| 
 | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :vm_memory_monitor, | ||||
|       :set_vm_memory_high_watermark, | ||||
|       [{:absolute, val}] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: ["set_vm_memory_high_watermark <fraction>", "set_vm_memory_high_watermark absolute <value>"] | ||||
|   def usage, | ||||
|     do: [ | ||||
|       "set_vm_memory_high_watermark <fraction>", | ||||
|       "set_vm_memory_high_watermark absolute <value>" | ||||
|     ] | ||||
| 
 | ||||
|   def banner(["absolute", arg], %{node: node_name}), do: "Setting memory threshold on #{node_name} to #{arg} bytes ..." | ||||
|   def banner([arg], %{node: node_name}), do: "Setting memory threshold on #{node_name} to #{arg} ..." | ||||
|   def banner(["absolute", arg], %{node: node_name}), | ||||
|     do: "Setting memory threshold on #{node_name} to #{arg} bytes ..." | ||||
| 
 | ||||
|   def banner([arg], %{node: node_name}), | ||||
|     do: "Setting memory threshold on #{node_name} to #{arg} ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.ShutdownCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   alias RabbitMQ.CLI.Core.OsPid | ||||
|  | @ -25,26 +24,30 @@ defmodule RabbitMQ.CLI.Ctl.Commands.ShutdownCommand do | |||
|     case :rabbit_misc.rpc_call(node_name, :os, :getpid, []) do | ||||
|       pid when is_list(pid) -> | ||||
|         shutdown_node_and_wait_pid_to_stop(node_name, pid) | ||||
|       other -> other | ||||
| 
 | ||||
|       other -> | ||||
|         other | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def shutdown_node_and_wait_pid_to_stop(node_name, pid) do | ||||
|     {:stream, | ||||
|       RabbitMQ.CLI.Core.Helpers.stream_until_error([ | ||||
|         fn() -> "Shutting down RabbitMQ node #{node_name} running at PID #{pid}" end, | ||||
|         fn() -> | ||||
|           res = :rabbit_misc.rpc_call(node_name, :rabbit, :stop_and_halt, []) | ||||
|           case res do | ||||
|             :ok               -> "Waiting for PID #{pid} to terminate"; | ||||
|             {:badrpc, err}    -> {:error, err} | ||||
|             {:error, _} = err -> err | ||||
|           end | ||||
|         end, | ||||
|         fn() -> | ||||
|           OsPid.wait_for_os_process_death(pid) | ||||
|           "RabbitMQ node #{node_name} running at PID #{pid} successfully shut down" | ||||
|         end])} | ||||
|      RabbitMQ.CLI.Core.Helpers.stream_until_error([ | ||||
|        fn -> "Shutting down RabbitMQ node #{node_name} running at PID #{pid}" end, | ||||
|        fn -> | ||||
|          res = :rabbit_misc.rpc_call(node_name, :rabbit, :stop_and_halt, []) | ||||
| 
 | ||||
|          case res do | ||||
|            :ok -> "Waiting for PID #{pid} to terminate" | ||||
|            {:badrpc, err} -> {:error, err} | ||||
|            {:error, _} = err -> err | ||||
|          end | ||||
|        end, | ||||
|        fn -> | ||||
|          OsPid.wait_for_os_process_death(pid) | ||||
|          "RabbitMQ node #{node_name} running at PID #{pid} successfully shut down" | ||||
|        end | ||||
|      ])} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  |  | |||
|  | @ -13,14 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.StartAppCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
|   def validate([_|_] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   def run([], %{node: node_name}) do | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.StatusCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -22,7 +21,7 @@ defmodule RabbitMQ.CLI.Ctl.Commands.StatusCommand do | |||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   def run([], %{node: node_name}) do | ||||
|  |  | |||
|  | @ -13,14 +13,12 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.StopAppCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
| 
 | ||||
|   def merge_defaults(args, opts), do: {args, opts} | ||||
|   def validate([_|_] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 0, do: {:validation_failure, :too_many_args} | ||||
|   def validate([], _), do: :ok | ||||
| 
 | ||||
|   def run([], %{node: node_name}) do | ||||
|  | @ -29,6 +27,5 @@ defmodule RabbitMQ.CLI.Ctl.Commands.StopAppCommand do | |||
| 
 | ||||
|   def usage, do: "stop_app" | ||||
| 
 | ||||
| 
 | ||||
|   def banner(_, %{node: node_name}), do: "Stopping rabbit application on node #{node_name} ..." | ||||
| end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.StopCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -27,27 +26,33 @@ defmodule RabbitMQ.CLI.Ctl.Commands.StopCommand do | |||
| 
 | ||||
|   def validate([], _), do: :ok | ||||
|   def validate([_pidfile_path], _), do: :ok | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   def run([], %{node: node_name, idempotent: true}) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit, :stop_and_halt, []) do | ||||
|       {:badrpc, :nodedown} -> {:ok, "Node #{node_name} is no longer running"}; | ||||
|       any                  -> any | ||||
|       {:badrpc, :nodedown} -> {:ok, "Node #{node_name} is no longer running"} | ||||
|       any -> any | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def run([], %{node: node_name, idempotent: false}) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit, :stop_and_halt, []) | ||||
|   end | ||||
| 
 | ||||
|   def run([pidfile_path], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, :rabbit, :stop_and_halt, []) | ||||
| 
 | ||||
|     case OsPid.read_pid_from_file(pidfile_path, true) do | ||||
|       {:error, details} -> {:error, "could not read pid from file #{pidfile_path}. Error: #{details}"}; | ||||
|       {:error, :could_not_read_pid_from_file, | ||||
|         {:contents, s}} -> {:error, "could not read pid from file #{pidfile_path}. File contents: #{s}"}; | ||||
|       {:error, :could_not_read_pid_from_file, | ||||
|         details}        -> {:error, "could not read pid from file #{pidfile_path}. Error: #{details}"}; | ||||
|       pid               -> | ||||
|       {:error, details} -> | ||||
|         {:error, "could not read pid from file #{pidfile_path}. Error: #{details}"} | ||||
| 
 | ||||
|       {:error, :could_not_read_pid_from_file, {:contents, s}} -> | ||||
|         {:error, "could not read pid from file #{pidfile_path}. File contents: #{s}"} | ||||
| 
 | ||||
|       {:error, :could_not_read_pid_from_file, details} -> | ||||
|         {:error, "could not read pid from file #{pidfile_path}. Error: #{details}"} | ||||
| 
 | ||||
|       pid -> | ||||
|         OsPid.wait_for_os_process_death(pid) | ||||
|         {:ok, "process #{pid} (take from pid file #{pidfile_path}) is no longer running"} | ||||
|     end | ||||
|  | @ -58,5 +63,6 @@ defmodule RabbitMQ.CLI.Ctl.Commands.StopCommand do | |||
|   def banner([pidfile_path], %{node: node_name}) do | ||||
|     "Stopping and halting node #{node_name} (will monitor pid file #{pidfile_path}) ..." | ||||
|   end | ||||
| 
 | ||||
|   def banner(_, %{node: node_name}), do: "Stopping and halting node #{node_name} ..." | ||||
| end | ||||
|  |  | |||
|  | @ -23,14 +23,15 @@ defmodule RabbitMQ.CLI.Ctl.Commands.SyncQueueCommand do | |||
|     {args, Map.merge(default_opts(), opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_], _), do: :ok | ||||
|   def validate(_, _),   do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([queue], %{vhost: vhost, node: node_name}) do | ||||
|     :rpc.call(node_name, | ||||
|     :rpc.call( | ||||
|       node_name, | ||||
|       :rabbit_mirror_queue_misc, | ||||
|       :sync_queue, | ||||
|       [:rabbit_misc.r(vhost, :queue, queue)], | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.TraceOffCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -22,14 +21,14 @@ defmodule RabbitMQ.CLI.Ctl.Commands.TraceOffCommand do | |||
|     {[], Map.merge(%{vhost: "/"}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, vhost: vhost}) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_trace, :stop, [vhost]) do | ||||
|       :ok   -> {:ok, "Trace disabled for vhost #{vhost}"}; | ||||
|       :ok -> {:ok, "Trace disabled for vhost #{vhost}"} | ||||
|       other -> other | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is GoPivotal, Inc. | ||||
| ## Copyright (c) 2007-2019 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.TraceOnCommand do | ||||
|   @behaviour RabbitMQ.CLI.CommandBehaviour | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
|  | @ -22,14 +21,14 @@ defmodule RabbitMQ.CLI.Ctl.Commands.TraceOnCommand do | |||
|     {[], Map.merge(%{vhost: "/"}, opts)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_|_], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate([_ | _], _), do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: :ok | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppRunning | ||||
| 
 | ||||
|   def run([], %{node: node_name, vhost: vhost}) do | ||||
|     case :rabbit_misc.rpc_call(node_name, :rabbit_trace, :start, [vhost]) do | ||||
|       :ok   -> {:ok, "Trace enabled for vhost #{vhost}"}; | ||||
|       :ok -> {:ok, "Trace enabled for vhost #{vhost}"} | ||||
|       other -> other | ||||
|     end | ||||
|   end | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ | |||
| ## The Initial Developer of the Original Code is Pivotal Software, Inc. | ||||
| ## Copyright (c) 2016-2017 Pivotal Software, Inc.  All rights reserved. | ||||
| 
 | ||||
| 
 | ||||
| defmodule RabbitMQ.CLI.Ctl.Commands.UpdateClusterNodesCommand do | ||||
|   alias RabbitMQ.CLI.Core.Helpers | ||||
| 
 | ||||
|  | @ -23,18 +22,19 @@ defmodule RabbitMQ.CLI.Ctl.Commands.UpdateClusterNodesCommand do | |||
|     {args, opts} | ||||
|   end | ||||
| 
 | ||||
|   def validate([], _),  do: {:validation_failure, :not_enough_args} | ||||
|   def validate([], _), do: {:validation_failure, :not_enough_args} | ||||
|   def validate([_], _), do: :ok | ||||
|   def validate(_, _),   do: {:validation_failure, :too_many_args} | ||||
|   def validate(_, _), do: {:validation_failure, :too_many_args} | ||||
| 
 | ||||
|   use RabbitMQ.CLI.Core.RequiresRabbitAppStopped | ||||
| 
 | ||||
|   def run([seed_node], %{node: node_name}) do | ||||
|     :rabbit_misc.rpc_call(node_name, | ||||
|         :rabbit_mnesia, | ||||
|         :update_cluster_nodes, | ||||
|         [Helpers.normalise_node(seed_node)] | ||||
|       ) | ||||
|     :rabbit_misc.rpc_call( | ||||
|       node_name, | ||||
|       :rabbit_mnesia, | ||||
|       :update_cluster_nodes, | ||||
|       [Helpers.normalise_node(seed_node)] | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def usage() do | ||||
|  | @ -46,12 +46,14 @@ defmodule RabbitMQ.CLI.Ctl.Commands.UpdateClusterNodesCommand do | |||
|   end | ||||
| 
 | ||||
|   def output({:error, :mnesia_unexpectedly_running}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      RabbitMQ.CLI.DefaultOutput.mnesia_running_error(node_name)} | ||||
|   end | ||||
| 
 | ||||
|   def output({:error, :cannot_cluster_node_with_itself}, %{node: node_name}) do | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, | ||||
|     {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), | ||||
|      "Error: cannot cluster node with itself: #{node_name}"} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| end | ||||
|  |  | |||
|  | @ -21,23 +21,25 @@ defmodule RabbitMQ.CLI.Ctl.Commands.WaitCommand do | |||
| 
 | ||||
|   def switches(), do: [pid: :integer, timeout: :integer] | ||||
| 
 | ||||
|   def aliases(), do: ['P': :pid, t: :timeout] | ||||
|   def aliases(), do: [P: :pid, t: :timeout] | ||||
| 
 | ||||
|   def scopes(), do: [:ctl, :diagnostics] | ||||
| 
 | ||||
|   def merge_defaults(args, opts) do | ||||
|     timeout = case opts[:timeout] do | ||||
|       nil       -> @default_timeout; | ||||
|       :infinity -> @default_timeout; | ||||
|       val       -> val | ||||
|     end | ||||
|     {args, Map.put(opts, :timeout, timeout)} | ||||
|  end | ||||
|     timeout = | ||||
|       case opts[:timeout] do | ||||
|         nil -> @default_timeout | ||||
|         :infinity -> @default_timeout | ||||
|         val -> val | ||||
|       end | ||||
| 
 | ||||
|   def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|     {args, Map.put(opts, :timeout, timeout)} | ||||
|   end | ||||
| 
 | ||||
|   def validate([_ | _] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} | ||||
|   def validate([_], %{pid: _}), do: {:validation_failure, "Cannot specify both pid and pidfile"} | ||||
|   def validate([],  %{pid: _} = opts), do: Validators.rabbit_is_loaded([], opts) | ||||
|   def validate([],  _), do: {:validation_failure, "No pid or pidfile specified"} | ||||
|   def validate([], %{pid: _} = opts), do: Validators.rabbit_is_loaded([], opts) | ||||
|   def validate([], _), do: {:validation_failure, "No pid or pidfile specified"} | ||||
|   def validate([_], opts), do: Validators.rabbit_is_loaded([], opts) | ||||
| 
 | ||||
|   def run([pid_file], %{node: node_name, timeout: timeout} = opts) do | ||||
|  | @ -47,45 +49,58 @@ defmodule RabbitMQ.CLI.Ctl.Commands.WaitCommand do | |||
|     Helpers.stream_until_error_parametrised( | ||||
|       [ | ||||
|         log("Waiting for pid file '#{pid_file}' to appear", quiet), | ||||
|         fn(_)   -> wait_for_pid_file(pid_file, timeout) end, | ||||
|         log_param(fn(pid) -> "pid is #{pid}" end, quiet), | ||||
|       ] | ||||
|       ++ | ||||
|       wait_for_pid_funs(node_name, app_names, timeout, quiet), | ||||
|       :init) | ||||
|         fn _ -> wait_for_pid_file(pid_file, timeout) end, | ||||
|         log_param(fn pid -> "pid is #{pid}" end, quiet) | ||||
|       ] ++ | ||||
|         wait_for_pid_funs(node_name, app_names, timeout, quiet), | ||||
|       :init | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def run([], %{node: node_name, pid: pid, timeout: timeout} = opts) do | ||||
|     app_names = :rabbit_and_plugins | ||||
|     quiet = opts[:quiet] || false | ||||
| 
 | ||||
|     Helpers.stream_until_error_parametrised( | ||||
|       wait_for_pid_funs(node_name, app_names, timeout, quiet), | ||||
|       pid) | ||||
|       pid | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   defp wait_for_pid_funs(node_name, app_names, timeout, quiet) do | ||||
|     app_names_formatted = :io_lib.format('~p', [app_names]) | ||||
| 
 | ||||
|     [ | ||||
|       log_param(fn(pid) -> "Waiting for erlang distribution on node '#{node_name}' while OS process '#{pid}' is running" end, quiet), | ||||
|       fn(pid) -> wait_for_erlang_distribution(pid, node_name, timeout) end, | ||||
|       log("Waiting for applications '#{app_names_formatted}' to start on node '#{node_name}'", quiet), | ||||
|       fn(_)   -> wait_for_application(node_name, app_names) end, | ||||
|       log_param( | ||||
|         fn pid -> | ||||
|           "Waiting for erlang distribution on node '#{node_name}' while OS process '#{pid}' is running" | ||||
|         end, | ||||
|         quiet | ||||
|       ), | ||||
|       fn pid -> wait_for_erlang_distribution(pid, node_name, timeout) end, | ||||
|       log( | ||||
|         "Waiting for applications '#{app_names_formatted}' to start on node '#{node_name}'", | ||||
|         quiet | ||||
|       ), | ||||
|       fn _ -> wait_for_application(node_name, app_names) end, | ||||
|       log("Applications '#{app_names_formatted}' are running on node '#{node_name}'", quiet) | ||||
|     ] | ||||
|   end | ||||
| 
 | ||||
|   defp log(_string, _quiet = true) do | ||||
|     fn(val) -> {:ok, val} end | ||||
|     fn val -> {:ok, val} end | ||||
|   end | ||||
| 
 | ||||
|   defp log(string, _quiet = false) do | ||||
|     fn(val) -> {:ok, val, string} end | ||||
|     fn val -> {:ok, val, string} end | ||||
|   end | ||||
| 
 | ||||
|   defp log_param(_fun, _quiet = true) do | ||||
|     fn(val) -> {:ok, val} end | ||||
|     fn val -> {:ok, val} end | ||||
|   end | ||||
| 
 | ||||
|   defp log_param(fun, _quiet = false) do | ||||
|     fn(val) -> {:ok, val, fun.(val)} end | ||||
|     fn val -> {:ok, val, fun.(val)} end | ||||
|   end | ||||
| 
 | ||||
|   def usage, do: "wait [<pid_file>] [--pid|-P <pid>]" | ||||
|  | @ -95,53 +110,62 @@ defmodule RabbitMQ.CLI.Ctl.Commands.WaitCommand do | |||
| 
 | ||||
|   def output({:error, err}, _opts) do | ||||
|     case format_error(err) do | ||||
|       :undefined -> RabbitMQ.CLI.DefaultOutput.output({:error, err}); | ||||
|       error_str  -> {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software, error_str} | ||||
|       :undefined -> RabbitMQ.CLI.DefaultOutput.output({:error, err}) | ||||
|       error_str -> {:error, RabbitMQ.CLI.Core.ExitCodes.exit_software(), error_str} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def output({:stream, stream}, _opts) do | ||||
|     {:stream, | ||||
|      Stream.map(stream, fn | ||||
|                         ({:error, err}) -> | ||||
|                           {:error, | ||||
|                            case format_error(err) do | ||||
|                              :undefined -> err; | ||||
|                              error_str  -> error_str | ||||
|                            end}; | ||||
|                         (other) -> other | ||||
|                         end)} | ||||
|        {:error, err} -> | ||||
|          {:error, | ||||
|           case format_error(err) do | ||||
|             :undefined -> err | ||||
|             error_str -> error_str | ||||
|           end} | ||||
| 
 | ||||
|        other -> | ||||
|          other | ||||
|      end)} | ||||
|   end | ||||
| 
 | ||||
|   use RabbitMQ.CLI.DefaultOutput | ||||
| 
 | ||||
|   defp format_error(:process_not_running) do | ||||
|     "Error: process is not running." | ||||
|   end | ||||
| 
 | ||||
|   defp format_error({:garbage_in_pid_file, _}) do | ||||
|     "Error: garbage in pid file." | ||||
|   end | ||||
| 
 | ||||
|   defp format_error({:could_not_read_pid, err}) do | ||||
|     "Error: could not read pid. Detail: #{err}" | ||||
|   end | ||||
| 
 | ||||
|   defp format_error(_) do | ||||
|     :undefined | ||||
|   end | ||||
| 
 | ||||
|   defp wait_for_application(node_name, :rabbit_and_plugins) do | ||||
|     case :rabbit.await_startup(node_name) do | ||||
|       {:badrpc, err} -> {:error, {:badrpc, err}}; | ||||
|       other          -> other | ||||
|       {:badrpc, err} -> {:error, {:badrpc, err}} | ||||
|       other -> other | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   defp wait_for_erlang_distribution(pid, node_name, timeout) do | ||||
|     wait_for(timeout, | ||||
|       fn() -> | ||||
|     wait_for( | ||||
|       timeout, | ||||
|       fn -> | ||||
|         case check_distribution(pid, node_name) do | ||||
|           # Loop while node is available. | ||||
|           {:error, :pang} -> {:error, :loop}; | ||||
|           other           -> other | ||||
|           {:error, :pang} -> {:error, :loop} | ||||
|           other -> other | ||||
|         end | ||||
|       end) | ||||
|       end | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   defp check_distribution(pid, node_name) do | ||||
|  | @ -150,8 +174,10 @@ defmodule RabbitMQ.CLI.Ctl.Commands.WaitCommand do | |||
|         case Node.ping(node_name) do | ||||
|           :pong -> :ok | ||||
|           :pang -> {:error, :pang} | ||||
|         end; | ||||
|       false -> {:error, :process_not_running} | ||||
|         end | ||||
| 
 | ||||
|       false -> | ||||
|         {:error, :process_not_running} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|  | @ -160,50 +186,69 @@ defmodule RabbitMQ.CLI.Ctl.Commands.WaitCommand do | |||
|   end | ||||
| 
 | ||||
|   defp wait_for_pid_file(pid_file, timeout) do | ||||
|     wait_for(timeout, | ||||
|       fn() -> | ||||
|     wait_for( | ||||
|       timeout, | ||||
|       fn -> | ||||
|         case :file.read_file(pid_file) do | ||||
|           {:ok, bin} -> | ||||
|             case Integer.parse(bin) do | ||||
|               :error -> | ||||
|                 {:error, {:garbage_in_pid_file, pid_file}} | ||||
|               {int, _} -> {:ok, int} | ||||
| 
 | ||||
|               {int, _} -> | ||||
|                 {:ok, int} | ||||
|             end | ||||
| 
 | ||||
|           {:error, :enoent} -> | ||||
|             {:error, :loop}; | ||||
|             {:error, :loop} | ||||
| 
 | ||||
|           {:error, err} -> | ||||
|             {:error, {:could_not_read_pid, err}} | ||||
|         end | ||||
|       end) | ||||
|       end | ||||
|     ) | ||||
|   end | ||||
| 
 | ||||
|   def wait_for(timeout, fun)  do | ||||
|   def wait_for(timeout, fun) do | ||||
|     sleep = round(timeout / 10) | ||||
| 
 | ||||
|     case wait_for_loop(timeout, sleep, fun) do | ||||
|       {:error, :timeout} -> {:error, {:timeout, timeout}} | ||||
|       other              -> other | ||||
|       other -> other | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def wait_for_loop(timeout, _, _) when timeout <= 0 do | ||||
|     {:error, :timeout} | ||||
|   end | ||||
| 
 | ||||
|   def wait_for_loop(timeout, sleep, fun) do | ||||
|     time  = :erlang.system_time(:milli_seconds) | ||||
|     time = :erlang.system_time(:milli_seconds) | ||||
| 
 | ||||
|     case fun.() do | ||||
|       {:error, :loop} -> | ||||
|         time_to_fun = :erlang.system_time(:milli_seconds) - time | ||||
|         time_taken = case {time_to_fun > timeout, time_to_fun > sleep} do | ||||
|           ## The function took longer than timeout | ||||
|           {true, _}      -> time_to_fun; | ||||
|           ## The function took longer than sleep | ||||
|           {false, true}  -> time_to_fun; | ||||
|           ## We need to sleep | ||||
|           {false, false} -> :timer.sleep(sleep) | ||||
|                             time_to_fun + sleep | ||||
|         end | ||||
|         wait_for_loop(timeout - time_taken, sleep, fun); | ||||
|       other -> other | ||||
| 
 | ||||
|         time_taken = | ||||
|           case {time_to_fun > timeout, time_to_fun > sleep} do | ||||
|             ## The function took longer than timeout | ||||
|             {true, _} -> | ||||
|               time_to_fun | ||||
| 
 | ||||
|             ## The function took longer than sleep | ||||
|             {false, true} -> | ||||
|               time_to_fun | ||||
| 
 | ||||
|             ## We need to sleep | ||||
|             {false, false} -> | ||||
|               :timer.sleep(sleep) | ||||
|               time_to_fun + sleep | ||||
|           end | ||||
| 
 | ||||
|         wait_for_loop(timeout - time_taken, sleep, fun) | ||||
| 
 | ||||
|       other -> | ||||
|         other | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -18,19 +18,22 @@ defmodule RabbitMQ.CLI.Ctl.InfoKeys do | |||
| 
 | ||||
|   def validate_info_keys(args, valid_keys) do | ||||
|     info_keys = prepare_info_keys(args) | ||||
| 
 | ||||
|     case invalid_info_keys(info_keys, valid_keys) do | ||||
|       [_|_] = bad_info_keys -> | ||||
|       [_ | _] = bad_info_keys -> | ||||
|         {:validation_failure, {:bad_info_key, bad_info_keys}} | ||||
|       [] -> {:ok, info_keys} | ||||
| 
 | ||||
|       [] -> | ||||
|         {:ok, info_keys} | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   def prepare_info_keys(args) do | ||||
|     args | ||||
|     |> Enum.flat_map(fn(arg) -> String.split(arg, ",", [trim: true]) end) | ||||
|     |> Enum.flat_map(fn arg -> String.split(arg, ",", trim: true) end) | ||||
|     |> Enum.map(&String.trim/1) | ||||
|     |> Enum.map(&String.to_atom/1) | ||||
|     |> Enum.uniq | ||||
|     |> Enum.uniq() | ||||
|   end | ||||
| 
 | ||||
|   def with_valid_info_keys(args, valid_keys, fun) do | ||||
|  | @ -43,17 +46,17 @@ defmodule RabbitMQ.CLI.Ctl.InfoKeys do | |||
|   defp invalid_info_keys(info_keys, valid_keys) do | ||||
|     MapSet.new(info_keys) | ||||
|     |> MapSet.difference(MapSet.new(valid_keys)) | ||||
|     |> MapSet.to_list | ||||
|     |> MapSet.to_list() | ||||
|   end | ||||
| 
 | ||||
|   def info_for_keys(item, []) do | ||||
|     item | ||||
|   end | ||||
| 
 | ||||
|   def info_for_keys([{_,_}|_] = item, info_keys) do | ||||
|   def info_for_keys([{_, _} | _] = item, info_keys) do | ||||
|     item | ||||
|     |> Enum.filter(fn({k, _}) -> Enum.member?(info_keys, k) end) | ||||
|     |> Enum.map(fn({k, v}) -> {k, format_info_item(v)} end) | ||||
|     |> Enum.filter(fn {k, _} -> Enum.member?(info_keys, k) end) | ||||
|     |> Enum.map(fn {k, v} -> {k, format_info_item(v)} end) | ||||
|   end | ||||
| 
 | ||||
|   defp format_info_item(resource(name: name)) do | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue