summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerhard Lazu <gerhard@users.noreply.github.com>2017-03-29 17:58:26 +0100
committerGitHub <noreply@github.com>2017-03-29 17:58:26 +0100
commitd2b155e0d3f8313905797a4e56a576e79d30c2fc (patch)
tree97bf37c9012a1b894a1a15c5b1bbbfcb3d3d2eaa
parent3c19685dcdeecbf64a67612627ac2208afaa3d38 (diff)
parent6c00bf57485c42ec641f83d095d3daacc605b585 (diff)
downloadrabbitmq-server-git-d2b155e0d3f8313905797a4e56a576e79d30c2fc.tar.gz
Merge pull request #1166 from rabbitmq/rabbitmq-server-1162
Introduce rabbitmqctl shutdown command.
-rw-r--r--src/rabbit_control_main.erl36
-rw-r--r--test/rabbitmqctl_shutdown_SUITE.erl104
2 files changed, 130 insertions, 10 deletions
diff --git a/src/rabbit_control_main.erl b/src/rabbit_control_main.erl
index d6bc81945e..a600ad5234 100644
--- a/src/rabbit_control_main.erl
+++ b/src/rabbit_control_main.erl
@@ -269,6 +269,22 @@ do_action(Command, Node, Args, Opts, Inform, Timeout) ->
action(Command, Node, Args, Opts, Inform)
end.
+shutdown_node_and_wait_pid_to_stop(Node, Pid, Inform) ->
+ Inform("Shutting down RabbitMQ node ~p running at PID ~p", [Node, Pid]),
+ Res = call(Node, {rabbit, stop_and_halt, []}),
+ case Res of
+ ok -> wait_for_process_death(Pid);
+ _ -> ok
+ end,
+ Res.
+
+action(shutdown, Node, [], _Opts, Inform) ->
+ case rpc:call(Node, os, getpid, []) of
+ Pid when is_list(Pid) ->
+ shutdown_node_and_wait_pid_to_stop(Node, Pid, Inform);
+ Error -> Error
+ end;
+
action(stop, Node, Args, _Opts, Inform) ->
Inform("Stopping and halting node ~p", [Node]),
Res = call(Node, {rabbit, stop_and_halt, []}),
@@ -290,14 +306,14 @@ action(start_app, Node, [], _Opts, Inform) ->
action(reset, Node, [], _Opts, Inform) ->
Inform("Resetting node ~p", [Node]),
- require_mnesia_stopped(Node,
+ require_mnesia_stopped(Node,
fun() ->
call(Node, {rabbit_mnesia, reset, []})
end);
action(force_reset, Node, [], _Opts, Inform) ->
Inform("Forcefully resetting node ~p", [Node]),
- require_mnesia_stopped(Node,
+ require_mnesia_stopped(Node,
fun() ->
call(Node, {rabbit_mnesia, force_reset, []})
end);
@@ -309,21 +325,21 @@ action(join_cluster, Node, [ClusterNodeS], Opts, Inform) ->
false -> disc
end,
Inform("Clustering node ~p with ~p", [Node, ClusterNode]),
- require_mnesia_stopped(Node,
+ require_mnesia_stopped(Node,
fun() ->
rpc_call(Node, rabbit_mnesia, join_cluster, [ClusterNode, NodeType])
end);
action(change_cluster_node_type, Node, ["ram"], _Opts, Inform) ->
Inform("Turning ~p into a ram node", [Node]),
- require_mnesia_stopped(Node,
+ require_mnesia_stopped(Node,
fun() ->
rpc_call(Node, rabbit_mnesia, change_cluster_node_type, [ram])
end);
action(change_cluster_node_type, Node, [Type], _Opts, Inform)
when Type =:= "disc" orelse Type =:= "disk" ->
Inform("Turning ~p into a disc node", [Node]),
- require_mnesia_stopped(Node,
+ require_mnesia_stopped(Node,
fun() ->
rpc_call(Node, rabbit_mnesia, change_cluster_node_type, [disc])
end);
@@ -331,7 +347,7 @@ action(change_cluster_node_type, Node, [Type], _Opts, Inform)
action(update_cluster_nodes, Node, [ClusterNodeS], _Opts, Inform) ->
ClusterNode = list_to_atom(ClusterNodeS),
Inform("Updating cluster nodes for ~p from ~p", [Node, ClusterNode]),
- require_mnesia_stopped(Node,
+ require_mnesia_stopped(Node,
fun() ->
rpc_call(Node, rabbit_mnesia, update_cluster_nodes, [ClusterNode])
end);
@@ -496,9 +512,9 @@ action(set_disk_free_limit, Node, ["mem_relative", Arg], _Opts, Inform) ->
_ -> Arg
end),
Inform("Setting disk free limit on ~p to ~p of total RAM", [Node, Frac]),
- rpc_call(Node,
- rabbit_disk_monitor,
- set_disk_free_limit,
+ rpc_call(Node,
+ rabbit_disk_monitor,
+ set_disk_free_limit,
[{mem_relative, Frac}]);
@@ -962,7 +978,7 @@ escape(Bin, IsEscaped) when is_binary(Bin) ->
escape(L, false) when is_list(L) ->
escape_char(lists:reverse(L), []);
escape(L, true) when is_list(L) ->
- L.
+ L.
escape_char([$\\ | T], Acc) ->
escape_char(T, [$\\, $\\ | Acc]);
diff --git a/test/rabbitmqctl_shutdown_SUITE.erl b/test/rabbitmqctl_shutdown_SUITE.erl
new file mode 100644
index 0000000000..6f681a697b
--- /dev/null
+++ b/test/rabbitmqctl_shutdown_SUITE.erl
@@ -0,0 +1,104 @@
+%% 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) 2016 Pivotal Software, Inc. All rights reserved.
+%%
+-module(rabbitmqctl_shutdown_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("amqp_client/include/amqp_client.hrl").
+
+-compile(export_all).
+
+all() ->
+ [
+ {group, shutdown_running_node}%,
+ % {group, shutdown_not_running_node}
+ ].
+
+groups() ->
+ StopTests = [
+ shutdown_fails_if_unable_to_contact_node,
+ shutdown_fails_if_unable_to_stop
+ ],
+ [
+ {shutdown_running_node, [],
+ % StopTests ++
+ [shutdown_running_node_ok]},
+ {shutdown_not_running_node, [], StopTests}
+ ].
+
+init_per_suite(Config) ->
+ rabbit_ct_helpers:log_environment(),
+ rabbit_ct_helpers:run_setup_steps(Config).
+
+end_per_suite(Config) ->
+ rabbit_ct_helpers:run_teardown_steps(Config).
+
+init_per_group(shutdown_running_node, Config) ->
+ rabbit_ct_helpers:set_config(Config, [
+ {rmq_nodename_suffix, ?MODULE},
+ {need_start, true}
+ ]);
+init_per_group(shutdown_not_running_node, Config) ->
+ rabbit_ct_helpers:set_config(Config, [
+ {rmq_nodename_suffix, ?MODULE}
+ ]).
+
+end_per_group(shutdown_running_node, Config) ->
+ rabbit_ct_helpers:run_teardown_steps(Config, []);
+end_per_group(shutdown_not_running_node, Config) ->
+ rabbit_ct_helpers:run_teardown_steps(Config, []).
+
+init_per_testcase(Testcase, Config0) ->
+ Config1 = case ?config(need_start, Config0) of
+ true ->
+ rabbit_ct_helpers:run_setup_steps(Config0,
+ rabbit_ct_broker_helpers:setup_steps() ++
+ [fun save_node/1]);
+ _ ->
+ rabbit_ct_helpers:set_config(Config0,
+ [{node, non_existent_node@localhost}])
+ end,
+ rabbit_ct_helpers:testcase_started(Config1, Testcase).
+
+end_per_testcase(Testcase, Config0) ->
+ Config1 = case ?config(need_start, Config0) of
+ true ->
+ rabbit_ct_helpers:run_teardown_steps(Config0,
+ rabbit_ct_broker_helpers:teardown_steps());
+ _ -> Config0
+ end,
+ rabbit_ct_helpers:testcase_finished(Config1, Testcase).
+
+save_node(Config) ->
+ Node = rabbit_ct_broker_helpers:get_node_config(Config, 0, nodename),
+ rabbit_ct_helpers:set_config(Config, [{node, Node}]).
+
+shutdown_running_node_ok(Config) ->
+ Node = ?config(node, Config),
+ Pid = node_pid(Node),
+ ok = rabbit_control_main:action(shutdown, Node, [], [], fun ct:pal/2),
+ false = erlang_pid_is_running(Pid),
+ false = node_is_running(Node).
+
+node_pid(Node) ->
+ Val = rpc:call(Node, os, getpid, []),
+ true = is_list(Val),
+ list_to_integer(Val).
+
+erlang_pid_is_running(Pid) ->
+ rabbit_misc:is_os_process_alive(integer_to_list(Pid)).
+
+node_is_running(Node) ->
+ net_adm:ping(Node) == pong.