Skip to content

Commit 3b7e8cb

Browse files
michaelklishinmergify[bot]
authored andcommitted
New health check CLI commands
(cherry picked from commit 07ec1b4)
1 parent 95fcf32 commit 3b7e8cb

File tree

4 files changed

+248
-0
lines changed

4 files changed

+248
-0
lines changed
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
## This Source Code Form is subject to the terms of the Mozilla Public
2+
## License, v. 2.0. If a copy of the MPL was not distributed with this
3+
## file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
##
5+
## Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
6+
7+
defmodule RabbitMQ.CLI.Diagnostics.Commands.CheckIfMetadataStoreIsInitializedCommand do
8+
@moduledoc """
9+
Exits with a non-zero code if the node reports that its metadata store
10+
has finished its initialization procedure.
11+
12+
This command is meant to be used in health checks.
13+
"""
14+
15+
@behaviour RabbitMQ.CLI.CommandBehaviour
16+
17+
use RabbitMQ.CLI.Core.AcceptsDefaultSwitchesAndTimeout
18+
use RabbitMQ.CLI.Core.MergesNoDefaults
19+
use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments
20+
21+
def run([], %{node: node_name, timeout: timeout}) do
22+
:rabbit_misc.rpc_call(node_name, :rabbit_db, :is_init_finished, [], timeout)
23+
end
24+
25+
def output(true, %{node: node_name} = _options) do
26+
{:ok, "Metadata store on node #{node_name} has completed its initialization"}
27+
end
28+
29+
def output(false, %{node: node_name} = _options) do
30+
{:error,
31+
"Metadata store on node #{node_name} reports to not yet have finished initialization"}
32+
end
33+
34+
use RabbitMQ.CLI.DefaultOutput
35+
36+
def help_section(), do: :observability_and_health_checks
37+
38+
def description(),
39+
do:
40+
"Health check that exits with a non-zero code if the metadata store on target node has not yet finished initializing"
41+
42+
def usage, do: "check_if_metadata_store_initialized"
43+
44+
def banner([], %{node: node_name}) do
45+
"Checking if metadata store on node #{node_name} has finished initializing ..."
46+
end
47+
end
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
## This Source Code Form is subject to the terms of the Mozilla Public
2+
## License, v. 2.0. If a copy of the MPL was not distributed with this
3+
## file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
##
5+
## Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
6+
7+
defmodule RabbitMQ.CLI.Diagnostics.Commands.CheckIfMetadataStoreIsInitializedWithDataCommand do
8+
@moduledoc """
9+
Exits with a non-zero code if the node reports that its metadata store
10+
has finished its initialization procedure.
11+
12+
This command is meant to be used in health checks.
13+
"""
14+
15+
@behaviour RabbitMQ.CLI.CommandBehaviour
16+
17+
use RabbitMQ.CLI.Core.AcceptsDefaultSwitchesAndTimeout
18+
use RabbitMQ.CLI.Core.MergesNoDefaults
19+
use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments
20+
21+
def run([], %{node: node_name, timeout: timeout}) do
22+
case :rabbit_misc.rpc_call(node_name, :rabbit_db, :is_init_finished, [], timeout) do
23+
{:badrpc, _} = err ->
24+
err
25+
26+
{:error, _} = err ->
27+
err
28+
29+
{:error, _, _} = err ->
30+
err
31+
32+
false -> false
33+
34+
true ->
35+
case :rabbit_misc.rpc_call(node_name, :rabbit_db_vhost, :count_all, [], timeout) do
36+
{:error, _} = err ->
37+
err
38+
39+
{:ok, n} ->
40+
(n > 0)
41+
end
42+
end
43+
end
44+
45+
def output(true, %{node: node_name} = _options) do
46+
{:ok, "Metadata store on node #{node_name} has completed its initialization"}
47+
end
48+
49+
def output(false, %{node: node_name} = _options) do
50+
{:error,
51+
"Metadata store on node #{node_name} reports to not yet have finished initialization"}
52+
end
53+
54+
use RabbitMQ.CLI.DefaultOutput
55+
56+
def help_section(), do: :observability_and_health_checks
57+
58+
def description(),
59+
do:
60+
"Health check that exits with a non-zero code if the metadata store on target node has not yet finished initializing"
61+
62+
def usage, do: "check_if_metadata_store_initialized"
63+
64+
def banner([], %{node: node_name}) do
65+
"Checking if metadata store on node #{node_name} has finished initializing ..."
66+
end
67+
end
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
## This Source Code Form is subject to the terms of the Mozilla Public
2+
## License, v. 2.0. If a copy of the MPL was not distributed with this
3+
## file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
##
5+
## Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
6+
7+
defmodule CheckIfMetadataStoreIsInitializedCommandTest do
8+
use ExUnit.Case, async: false
9+
import TestHelper
10+
11+
@command RabbitMQ.CLI.Diagnostics.Commands.CheckIfMetadataStoreIsInitializedCommand
12+
13+
setup_all do
14+
RabbitMQ.CLI.Core.Distribution.start()
15+
16+
start_rabbitmq_app()
17+
18+
on_exit([], fn ->
19+
start_rabbitmq_app()
20+
end)
21+
22+
:ok
23+
end
24+
25+
setup context do
26+
{:ok,
27+
opts: %{
28+
node: get_rabbit_hostname(),
29+
timeout: context[:test_timeout] || 30000
30+
}}
31+
end
32+
33+
test "merge_defaults: nothing to do" do
34+
assert @command.merge_defaults([], %{}) == {[], %{}}
35+
end
36+
37+
test "validate: treats positional arguments as a failure" do
38+
assert @command.validate(["extra-arg"], %{}) == {:validation_failure, :too_many_args}
39+
end
40+
41+
test "validate: treats empty positional arguments and default switches as a success" do
42+
assert @command.validate([], %{}) == :ok
43+
end
44+
45+
@tag test_timeout: 3000
46+
test "run: targeting an unreachable node throws a badrpc", context do
47+
assert match?(
48+
{:badrpc, _},
49+
@command.run([], Map.merge(context[:opts], %{node: :jake@thedog}))
50+
)
51+
end
52+
53+
test "run: when the RabbitMQ app is booted and started, returns true", context do
54+
await_rabbitmq_startup()
55+
56+
assert @command.run([], context[:opts])
57+
end
58+
59+
test "output: when the result is true, returns successfully", context do
60+
assert match?({:ok, _}, @command.output(true, context[:opts]))
61+
end
62+
63+
# this is a check command
64+
test "output: when the result is false, returns an error", context do
65+
assert match?({:error, _}, @command.output(false, context[:opts]))
66+
end
67+
end
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
## This Source Code Form is subject to the terms of the Mozilla Public
2+
## License, v. 2.0. If a copy of the MPL was not distributed with this
3+
## file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
##
5+
## Copyright (c) 2007-2025 Broadcom. All Rights Reserved. The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. All rights reserved.
6+
7+
defmodule CheckIfMetadataStoreIsInitializedWithDataCommandTest do
8+
use ExUnit.Case, async: false
9+
import TestHelper
10+
11+
@command RabbitMQ.CLI.Diagnostics.Commands.CheckIfMetadataStoreIsInitializedWithDataCommand
12+
13+
setup_all do
14+
RabbitMQ.CLI.Core.Distribution.start()
15+
16+
start_rabbitmq_app()
17+
18+
on_exit([], fn ->
19+
start_rabbitmq_app()
20+
end)
21+
22+
:ok
23+
end
24+
25+
setup context do
26+
{:ok,
27+
opts: %{
28+
node: get_rabbit_hostname(),
29+
timeout: context[:test_timeout] || 30000
30+
}}
31+
end
32+
33+
test "merge_defaults: nothing to do" do
34+
assert @command.merge_defaults([], %{}) == {[], %{}}
35+
end
36+
37+
test "validate: treats positional arguments as a failure" do
38+
assert @command.validate(["extra-arg"], %{}) == {:validation_failure, :too_many_args}
39+
end
40+
41+
test "validate: treats empty positional arguments and default switches as a success" do
42+
assert @command.validate([], %{}) == :ok
43+
end
44+
45+
@tag test_timeout: 3000
46+
test "run: targeting an unreachable node throws a badrpc", context do
47+
assert match?(
48+
{:badrpc, _},
49+
@command.run([], Map.merge(context[:opts], %{node: :jake@thedog}))
50+
)
51+
end
52+
53+
test "run: when the RabbitMQ app is booted and started, returns true", context do
54+
await_rabbitmq_startup()
55+
56+
assert @command.run([], context[:opts])
57+
end
58+
59+
test "output: when the result is true, returns successfully", context do
60+
assert match?({:ok, _}, @command.output(true, context[:opts]))
61+
end
62+
63+
# this is a check command
64+
test "output: when the result is false, returns an error", context do
65+
assert match?({:error, _}, @command.output(false, context[:opts]))
66+
end
67+
end

0 commit comments

Comments
 (0)