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-2021 VMware, Inc. or its affiliates.  All rights reserved.
6
7defmodule RabbitMQ.CLI.Diagnostics.Commands.CheckLocalAlarmsCommand do
8  @moduledoc """
9  Exits with a non-zero code if the target node reports any local alarms.
10
11  This command is meant to be used in health checks.
12  """
13
14  import RabbitMQ.CLI.Core.Alarms
15  import RabbitMQ.CLI.Core.Platform, only: [line_separator: 0]
16
17  @behaviour RabbitMQ.CLI.CommandBehaviour
18
19  use RabbitMQ.CLI.Core.AcceptsDefaultSwitchesAndTimeout
20  use RabbitMQ.CLI.Core.MergesNoDefaults
21  use RabbitMQ.CLI.Core.AcceptsNoPositionalArguments
22  use RabbitMQ.CLI.Core.RequiresRabbitAppRunning
23
24  def run([], %{node: node_name, timeout: timeout}) do
25    # Example response when there are alarms:
26    #
27    # [
28    #  file_descriptor_limit,
29    #  {{resource_limit,disk,hare@warp10},[]},
30    #  {{resource_limit,memory,hare@warp10},[]},
31    #  {{resource_limit,disk,rabbit@warp10},[]},
32    #  {{resource_limit,memory,rabbit@warp10},[]}
33    # ]
34    #
35    # The topmost file_descriptor_limit alarm is node-local.
36    case :rabbit_misc.rpc_call(node_name, :rabbit_alarm, :get_alarms, [], timeout) do
37      [] -> []
38      xs when is_list(xs) -> local_alarms(xs, node_name)
39      other -> other
40    end
41  end
42
43  def output([], %{formatter: "json"}) do
44    {:ok, %{"result" => "ok"}}
45  end
46
47  def output([], %{silent: true}) do
48    {:ok, :check_passed}
49  end
50
51  def output([], %{node: node_name}) do
52    {:ok, "Node #{node_name} reported no local alarms"}
53  end
54
55  def output(alarms, %{node: node_name, formatter: "json"}) do
56    {:error, :check_failed,
57     %{
58       "result" => "error",
59       "local" => alarm_lines(alarms, node_name),
60       "message" => "Node #{node_name} reported local alarms"
61     }}
62  end
63
64  def output(_alarms, %{silent: true}) do
65    {:error, :check_failed}
66  end
67
68  def output(alarms, %{node: node_name}) do
69    lines = alarm_lines(alarms, node_name)
70
71    {:error, Enum.join(lines, line_separator())}
72  end
73
74  use RabbitMQ.CLI.DefaultOutput
75
76  def help_section(), do: :observability_and_health_checks
77
78  def description(), do: "Health check that exits with a non-zero code if the target node reports any local alarms"
79
80  def usage, do: "check_local_alarms"
81
82  def banner([], %{node: node_name}) do
83    "Asking node #{node_name} to report any local resource alarms ..."
84  end
85end
86