diff --git a/deps/rabbitmq_cli/lib/clear_permissions_command.ex b/deps/rabbitmq_cli/lib/clear_permissions_command.ex index b3ff1c2773..a2888a4e13 100644 --- a/deps/rabbitmq_cli/lib/clear_permissions_command.ex +++ b/deps/rabbitmq_cli/lib/clear_permissions_command.ex @@ -24,13 +24,13 @@ defmodule ClearPermissionsCommand do def validate([], _) do {:validation_failure, :not_enough_args} end - def switches(), do: [] - def validate([_|_] = args, _) when length(args) > 1 do {:validation_failure, :too_many_args} end def validate([_], _), do: :ok + def switches(), do: [] + def run([username], %{node: node_name, vhost: vhost}) do node_name |> Helpers.parse_node diff --git a/deps/rabbitmq_cli/lib/parser.ex b/deps/rabbitmq_cli/lib/parser.ex index f718bff4cd..a019d73f9c 100644 --- a/deps/rabbitmq_cli/lib/parser.ex +++ b/deps/rabbitmq_cli/lib/parser.ex @@ -31,7 +31,7 @@ defmodule Parser do defp build_switches(default) do Enum.reduce(Helpers.commands, default, - fn({_, command}, {:error, _} = err) -> err; + fn({_, _}, {:error, _} = err) -> err; ({_, command}, switches) -> command_switches = command.switches() case Enum.filter(command_switches, diff --git a/deps/rabbitmq_cli/lib/rabbitmqctl.ex b/deps/rabbitmq_cli/lib/rabbitmqctl.ex index f7e2b7e0d2..f225223193 100644 --- a/deps/rabbitmq_cli/lib/rabbitmqctl.ex +++ b/deps/rabbitmq_cli/lib/rabbitmqctl.ex @@ -130,6 +130,21 @@ defmodule RabbitMQCtl do result end + 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 + defp print_standard_messages({:healthcheck_failed, message} = result, _) do IO.puts "Error: healthcheck failed. Message: #{message}" result diff --git a/deps/rabbitmq_cli/lib/wait_command.ex b/deps/rabbitmq_cli/lib/wait_command.ex new file mode 100644 index 0000000000..5dd598ddc9 --- /dev/null +++ b/deps/rabbitmq_cli/lib/wait_command.ex @@ -0,0 +1,84 @@ +## 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. + + +defmodule WaitCommand do + @behaviour CommandBehaviour + @flags [] + + def merge_defaults(args, opts), do: {args, opts} + + def validate([_|_] = args, _) when length(args) > 1, do: {:validation_failure, :too_many_args} + def validate([], _), do: {:validation_failure, :not_enough_args} + def validate([_], _), do: :ok + + def switches(), do: [] + + def run([pid_file], %{node: node_name}) do + node_name + |> Helpers.parse_node + |> wait_for_application(pid_file, :rabbit_and_plugins); + end + + def usage, do: "wait " + + def flags, do: @flags + + def banner(_, %{node: node_name}), do: "Waiting for node #{node_name} ..." + + defp wait_for_application(node, pid_file, :rabbit_and_plugins) do + case read_pid_file(pid_file, true) do + {:error, _} = err -> err + pid -> + IO.puts "pid is #{pid}" + wait_for_startup(node, pid) + end + end + + defp wait_for_startup(node, pid) do + while_process_is_alive( + node, pid, fn() -> :rpc.call(node, :rabbit, :await_startup, []) == :ok end) + end + + defp while_process_is_alive(node, pid, activity) do + case :rabbit_misc.is_os_process_alive(pid) do + true -> + case activity.() do + true -> :ok + false -> + :timer.sleep(1000) + while_process_is_alive(node, pid, activity) + end + false -> {:error, :process_not_running} + end + end + + defp read_pid_file(pid_file, wait) do + case {:file.read_file(pid_file), wait} do + {{:ok, bin}, _} -> + case Integer.parse(bin) do + :error -> + {:error, {:garbage_in_pid_file, pid_file}} + {int, _} -> Integer.to_char_list int + end + {{:error, :enoent}, true} -> + :timer.sleep(1000) + read_pid_file(pid_file, wait) + {{:error, err}, _} -> + {:error, {:could_not_read_pid, err}} + end + end + +end diff --git a/deps/rabbitmq_cli/test/wait_command_test.exs b/deps/rabbitmq_cli/test/wait_command_test.exs new file mode 100644 index 0000000000..61783b6bdc --- /dev/null +++ b/deps/rabbitmq_cli/test/wait_command_test.exs @@ -0,0 +1,47 @@ +## 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. + + +defmodule WaitCommandTest do + use ExUnit.Case, async: false + import TestHelper + + @command WaitCommand + + setup_all do + :net_kernel.start([:rabbitmqctl, :shortnames]) + :net_kernel.connect_node(get_rabbit_hostname) + + on_exit([], fn -> + :erlang.disconnect_node(get_rabbit_hostname) + :net_kernel.stop() + end) + + :ok + end + + setup do + {:ok, opts: %{node: get_rabbit_hostname}} + end + + test "validate: with extra arguments returns an arg count error", context do + assert @command.validate(["pid_file", "extra"], context[:opts]) == {:validation_failure, :too_many_args} + assert @command.validate([], context[:opts]) == {:validation_failure, :not_enough_args} + end + + test "banner", context do + assert @command.banner([], context[:opts]) =~ ~r/Waiting for node #{get_rabbit_hostname}/ + end +end