2016-02-03 23:01:32 +08:00
|
|
|
## The contents of this file are subject to the Mozilla Public License
|
|
|
|
## Version 1.1 (the "License"); you may not use this file except in
|
|
|
|
## compliance with the License. You may obtain a copy of the License
|
|
|
|
## at http://www.mozilla.org/MPL/
|
|
|
|
##
|
|
|
|
## Software distributed under the License is distributed on an "AS IS"
|
|
|
|
## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
|
|
## the License for the specific language governing rights and
|
|
|
|
## limitations under the License.
|
|
|
|
##
|
|
|
|
## The Original Code is RabbitMQ.
|
|
|
|
##
|
|
|
|
## The Initial Developer of the Original Code is GoPivotal, Inc.
|
|
|
|
## Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved.
|
|
|
|
|
|
|
|
|
2016-02-03 22:42:45 +08:00
|
|
|
defmodule RabbitMQCtl do
|
2016-02-03 02:54:36 +08:00
|
|
|
import Parser
|
|
|
|
import Helpers
|
2016-03-23 00:21:12 +08:00
|
|
|
import ExitCodes
|
2016-02-03 02:54:36 +08:00
|
|
|
|
2016-05-09 18:07:46 +08:00
|
|
|
def main(unparsed_command) do
|
2016-02-03 22:42:45 +08:00
|
|
|
:net_kernel.start([:rabbitmqctl, :shortnames])
|
2016-02-03 02:54:36 +08:00
|
|
|
|
2016-05-27 05:02:10 +08:00
|
|
|
{parsed_cmd, options, invalid} = parse(unparsed_command)
|
|
|
|
case {Helpers.is_command?(parsed_cmd), invalid} do
|
2016-05-26 07:04:24 +08:00
|
|
|
{false, _} -> HelpCommand.all_usage() |> handle_exit(exit_usage);
|
2016-05-27 05:02:10 +08:00
|
|
|
{_, [_|_]} -> print_standard_messages({:bad_option, invalid}, unparsed_command)
|
|
|
|
|> handle_exit
|
|
|
|
{true, []} -> options
|
2016-05-27 19:10:11 +08:00
|
|
|
|> merge_defaults_defaults
|
2016-05-27 05:02:10 +08:00
|
|
|
|> run_command(parsed_cmd)
|
|
|
|
|> StandardCodes.map_to_standard_code
|
|
|
|
|> print_standard_messages(unparsed_command)
|
|
|
|
|> handle_exit
|
2016-03-05 05:35:54 +08:00
|
|
|
end
|
2016-02-03 05:32:35 +08:00
|
|
|
end
|
|
|
|
|
2016-05-24 19:33:11 +08:00
|
|
|
def merge_defaults_defaults(%{} = options) do
|
2016-03-08 03:08:38 +08:00
|
|
|
options
|
2016-05-24 19:33:11 +08:00
|
|
|
|> merge_defaults_node
|
|
|
|
|> merge_defaults_timeout
|
2016-03-08 03:08:38 +08:00
|
|
|
end
|
|
|
|
|
2016-05-24 19:33:11 +08:00
|
|
|
defp merge_defaults_node(%{} = opts), do: Map.merge(%{node: get_rabbit_hostname}, opts)
|
2016-03-08 06:45:50 +08:00
|
|
|
|
2016-05-24 19:33:11 +08:00
|
|
|
defp merge_defaults_timeout(%{} = opts), do: Map.merge(%{timeout: :infinity}, opts)
|
2016-03-08 06:45:50 +08:00
|
|
|
|
2016-06-02 06:38:09 +08:00
|
|
|
defp maybe_connect_to_rabbitmq("help", _), do: nil
|
2016-05-31 16:40:48 +08:00
|
|
|
defp maybe_connect_to_rabbitmq(_, node) do
|
|
|
|
Helpers.connect_to_rabbitmq(node)
|
|
|
|
end
|
|
|
|
|
2016-05-26 07:04:24 +08:00
|
|
|
defp run_command(_, []), do: HelpCommand.all_usage()
|
2016-05-06 01:17:50 +08:00
|
|
|
defp run_command(options, [command_name | arguments]) do
|
2016-05-09 18:07:46 +08:00
|
|
|
with_command(command_name,
|
|
|
|
fn(command) ->
|
|
|
|
case invalid_flags(command, options) do
|
2016-05-26 07:04:24 +08:00
|
|
|
[] ->
|
2016-05-24 19:33:11 +08:00
|
|
|
case command.validate(arguments, options) do
|
|
|
|
:ok ->
|
|
|
|
{arguments, options} = command.merge_defaults(arguments, options)
|
|
|
|
print_banner(command, arguments, options)
|
2016-05-31 16:40:48 +08:00
|
|
|
maybe_connect_to_rabbitmq(command_name, options[:node])
|
2016-05-24 19:33:11 +08:00
|
|
|
execute_command(command, arguments, options)
|
|
|
|
err -> err
|
|
|
|
end
|
2016-05-09 18:07:46 +08:00
|
|
|
result -> {:bad_option, result}
|
|
|
|
end
|
|
|
|
end)
|
2016-02-03 02:54:36 +08:00
|
|
|
end
|
2016-02-26 05:16:25 +08:00
|
|
|
|
2016-05-09 18:07:46 +08:00
|
|
|
defp with_command(command_name, fun) do
|
|
|
|
command = Helpers.commands[command_name]
|
2016-05-26 07:04:24 +08:00
|
|
|
fun.(command)
|
2016-05-05 06:31:11 +08:00
|
|
|
end
|
2016-04-27 02:38:23 +08:00
|
|
|
|
2016-05-24 19:33:11 +08:00
|
|
|
defp print_banner(command, args, opts) do
|
2016-05-31 16:40:48 +08:00
|
|
|
case command.banner(args, opts) do
|
2016-06-02 06:38:09 +08:00
|
|
|
nil -> nil
|
2016-05-31 16:40:48 +08:00
|
|
|
banner -> IO.inspect banner
|
|
|
|
end
|
2016-05-24 19:33:11 +08:00
|
|
|
end
|
|
|
|
|
2016-05-09 18:07:46 +08:00
|
|
|
defp execute_command(command, arguments, options) do
|
|
|
|
command.run(arguments, options)
|
|
|
|
end
|
|
|
|
|
2016-04-27 02:38:23 +08:00
|
|
|
defp print_standard_messages({:badrpc, :nodedown} = result, unparsed_command) do
|
2016-05-27 05:02:10 +08:00
|
|
|
{_, options, _} = parse(unparsed_command)
|
2016-03-09 01:15:56 +08:00
|
|
|
|
|
|
|
IO.puts "Error: unable to connect to node '#{options[:node]}': nodedown"
|
2016-04-27 02:38:23 +08:00
|
|
|
result
|
2016-03-09 01:15:56 +08:00
|
|
|
end
|
|
|
|
|
2016-04-27 02:38:23 +08:00
|
|
|
defp print_standard_messages({:badrpc, :timeout} = result, unparsed_command) do
|
2016-05-27 05:02:10 +08:00
|
|
|
{_, options, _} = parse(unparsed_command)
|
2016-04-27 02:38:23 +08:00
|
|
|
|
2016-03-09 01:15:56 +08:00
|
|
|
IO.puts "Error: {timeout, #{options[:timeout]}}"
|
2016-04-27 02:38:23 +08:00
|
|
|
result
|
2016-03-09 01:15:56 +08:00
|
|
|
end
|
2016-03-22 01:59:22 +08:00
|
|
|
|
2016-05-09 23:38:37 +08:00
|
|
|
defp print_standard_messages({:too_many_args, _} = result, unparsed_command) do
|
2016-05-27 05:02:10 +08:00
|
|
|
{[cmd | _], _, _} = parse(unparsed_command)
|
2016-05-09 23:38:37 +08:00
|
|
|
|
2016-04-27 02:38:23 +08:00
|
|
|
IO.puts "Error: too many arguments."
|
2016-04-30 02:08:42 +08:00
|
|
|
IO.puts "Given:\n\t#{unparsed_command |> Enum.join(" ")}"
|
2016-05-26 07:28:20 +08:00
|
|
|
HelpCommand.run([cmd], %{})
|
2016-04-27 02:38:23 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-05-09 23:38:37 +08:00
|
|
|
defp print_standard_messages({:not_enough_args, _} = result, unparsed_command) do
|
2016-05-27 05:02:10 +08:00
|
|
|
{[cmd | _], _, _} = parse(unparsed_command)
|
2016-05-09 23:38:37 +08:00
|
|
|
|
2016-04-27 02:38:23 +08:00
|
|
|
IO.puts "Error: not enough arguments."
|
2016-04-30 02:08:42 +08:00
|
|
|
IO.puts "Given:\n\t#{unparsed_command |> Enum.join(" ")}"
|
2016-05-26 07:28:20 +08:00
|
|
|
HelpCommand.run([cmd], %{})
|
|
|
|
|
2016-04-27 02:38:23 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
defp print_standard_messages({:refused, user, _, _} = result, _) do
|
2016-04-02 01:58:47 +08:00
|
|
|
IO.puts "Error: failed to authenticate user \"#{user}\""
|
2016-04-27 02:38:23 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-06-06 22:02:58 +08:00
|
|
|
defp print_standard_messages(
|
|
|
|
{failed_command,
|
|
|
|
{:mnesia_unexpectedly_running, node_name}} = result, _)
|
|
|
|
when
|
|
|
|
failed_command == :reset_failed or
|
|
|
|
failed_command == :join_cluster_failed
|
|
|
|
do
|
2016-06-02 18:19:07 +08:00
|
|
|
IO.puts "Mnesia is still running on node #{node_name}."
|
2016-06-06 22:00:50 +08:00
|
|
|
IO.puts "Please stop RabbitMQ with rabbitmqctl stop_app first."
|
2016-06-02 18:19:07 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-06-02 22:36:52 +08:00
|
|
|
defp print_standard_messages({:error, :process_not_running} = result, _) do
|
|
|
|
IO.puts "Error: process is not running."
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
defp print_standard_messages({:error, {:garbage_in_pid_file, _}} = result, _) do
|
|
|
|
IO.puts "Error: garbage in pid file."
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
defp print_standard_messages({:error, {:could_not_read_pid, err}} = result, _) do
|
|
|
|
IO.puts "Error: could not read pid. Detail: #{err}"
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-06-02 06:38:09 +08:00
|
|
|
defp print_standard_messages({:healthcheck_failed, message} = result, _) do
|
|
|
|
IO.puts "Error: healthcheck failed. Message: #{message}"
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-05-09 23:07:49 +08:00
|
|
|
defp print_standard_messages({:bad_option, _} = result, unparsed_command) do
|
2016-05-27 05:02:10 +08:00
|
|
|
{[cmd | _], _, _} = parse(unparsed_command)
|
2016-05-09 23:07:49 +08:00
|
|
|
|
2016-05-05 03:40:09 +08:00
|
|
|
IO.puts "Error: invalid options for this command."
|
|
|
|
IO.puts "Given:\n\t#{unparsed_command |> Enum.join(" ")}"
|
2016-05-26 07:28:20 +08:00
|
|
|
HelpCommand.run([cmd], %{})
|
2016-05-05 03:40:09 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-05-24 19:33:11 +08:00
|
|
|
defp print_standard_messages({:validation_failure, err_detail} = result, unparsed_command) do
|
2016-05-30 07:16:10 +08:00
|
|
|
{[command_name | _], _, _} = parse(unparsed_command)
|
|
|
|
err = format_validation_error(err_detail) # TODO format the error better
|
2016-05-24 19:33:11 +08:00
|
|
|
IO.puts "Error: #{err}"
|
|
|
|
IO.puts "Given:\n\t#{unparsed_command |> Enum.join(" ")}"
|
2016-05-30 07:16:10 +08:00
|
|
|
|
|
|
|
case Helpers.is_command?(command_name) do
|
|
|
|
true ->
|
|
|
|
command = Helpers.commands[command_name]
|
|
|
|
HelpCommand.print_base_usage(command)
|
|
|
|
false ->
|
|
|
|
HelpCommand.all_usage()
|
|
|
|
ExitCodes.exit_usage
|
|
|
|
end
|
|
|
|
|
2016-05-24 19:33:11 +08:00
|
|
|
result
|
|
|
|
end
|
|
|
|
|
2016-04-27 02:38:23 +08:00
|
|
|
defp print_standard_messages(result, _) do
|
|
|
|
result
|
2016-04-02 01:58:47 +08:00
|
|
|
end
|
|
|
|
|
2016-05-24 19:33:11 +08:00
|
|
|
defp format_validation_error(:not_enough_args), do: "not enough arguments."
|
|
|
|
defp format_validation_error({:not_enough_args, detail}), do: "not enough arguments. #{detail}"
|
|
|
|
defp format_validation_error(:too_many_args), do: "too many arguments."
|
|
|
|
defp format_validation_error({:too_many_args, detail}), do: "too many arguments. #{detail}"
|
|
|
|
defp format_validation_error(:bad_argument), do: "Bad argument."
|
|
|
|
defp format_validation_error({:bad_argument, detail}), do: "Bad argument. #{detail}"
|
|
|
|
defp format_validation_error(err), do: inspect err
|
|
|
|
|
|
|
|
defp handle_exit({:validation_failure, :not_enough_args}), do: exit_program(exit_usage)
|
|
|
|
defp handle_exit({:validation_failure, :too_many_args}), do: exit_program(exit_usage)
|
|
|
|
defp handle_exit({:validation_failure, {:not_enough_args, _}}), do: exit_program(exit_usage)
|
|
|
|
defp handle_exit({:validation_failure, {:too_many_args, _}}), do: exit_program(exit_usage)
|
|
|
|
defp handle_exit({:validation_failure, {:bad_argument, _}}), do: exit_program(exit_dataerr)
|
|
|
|
defp handle_exit({:validation_failure, :bad_argument}), do: exit_program(exit_dataerr)
|
|
|
|
defp handle_exit({:validation_failure, _}), do: exit_program(exit_usage)
|
2016-05-05 03:40:09 +08:00
|
|
|
defp handle_exit({:bad_option, _}), do: exit_program(exit_usage)
|
2016-03-23 00:21:12 +08:00
|
|
|
defp handle_exit({:badrpc, :timeout}), do: exit_program(exit_tempfail)
|
|
|
|
defp handle_exit({:badrpc, :nodedown}), do: exit_program(exit_unavailable)
|
2016-04-02 01:58:47 +08:00
|
|
|
defp handle_exit({:refused, _, _, _}), do: exit_program(exit_dataerr)
|
2016-06-02 06:38:09 +08:00
|
|
|
defp handle_exit({:healthcheck_failed, _}), do: exit_program(exit_software)
|
2016-06-06 22:02:58 +08:00
|
|
|
defp handle_exit({:join_cluster_failed, _}), do: exit_program(exit_software)
|
2016-06-02 18:19:07 +08:00
|
|
|
defp handle_exit({:reset_failed, _}), do: exit_program(exit_software)
|
2016-03-23 00:21:12 +08:00
|
|
|
defp handle_exit({:error, _}), do: exit_program(exit_software)
|
2016-06-02 06:38:09 +08:00
|
|
|
defp handle_exit(true), do: handle_exit(:ok, exit_ok)
|
2016-04-02 01:42:25 +08:00
|
|
|
defp handle_exit(:ok), do: handle_exit(:ok, exit_ok)
|
|
|
|
defp handle_exit({:ok, result}), do: handle_exit({:ok, result}, exit_ok)
|
|
|
|
defp handle_exit(result) when is_list(result), do: handle_exit({:ok, result}, exit_ok)
|
2016-03-23 00:21:12 +08:00
|
|
|
defp handle_exit(:ok, code), do: exit_program(code)
|
|
|
|
defp handle_exit({:ok, result}, code) do
|
2016-05-26 03:03:17 +08:00
|
|
|
case Enumerable.impl_for(result) do
|
|
|
|
nil -> IO.inspect result;
|
|
|
|
_ -> result |> Stream.map(&IO.inspect/1) |> Stream.run
|
|
|
|
end
|
2016-03-23 00:21:12 +08:00
|
|
|
exit_program(code)
|
|
|
|
end
|
|
|
|
|
2016-05-05 18:39:27 +08:00
|
|
|
defp invalid_flags(command, opts) do
|
2016-05-26 03:03:17 +08:00
|
|
|
Map.keys(opts) -- (command.flags ++ Helpers.global_flags)
|
2016-05-05 03:40:09 +08:00
|
|
|
end
|
|
|
|
|
2016-03-23 00:21:12 +08:00
|
|
|
defp exit_program(code) do
|
|
|
|
:net_kernel.stop
|
2016-04-02 00:13:01 +08:00
|
|
|
exit({:shutdown, code})
|
2016-03-23 00:21:12 +08:00
|
|
|
end
|
2016-02-03 02:54:36 +08:00
|
|
|
end
|