2019-01-22 16:39:19 +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-2019 Pivotal Software, Inc. All rights reserved.
|
|
|
|
|
|
|
|
|
|
defmodule RabbitMQ.CLI.Diagnostics.Helpers do
|
|
|
|
|
import RabbitCommon.Records
|
|
|
|
|
import Rabbitmq.Atom.Coerce
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Listeners
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
def listeners_on(listeners, target_node) do
|
|
|
|
|
Enum.filter(listeners, fn listener(node: node) ->
|
|
|
|
|
node == target_node
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def listener_lines(listeners) do
|
|
|
|
|
listeners |> listener_maps |>
|
|
|
|
|
Enum.map(fn %{interface: interface, port: port, protocol: protocol} ->
|
2019-01-22 17:04:43 +08:00
|
|
|
"Interface: #{interface}, port: #{port}, protocol: #{protocol}, purpose: #{protocol_label(to_atom(protocol))}"
|
2019-01-22 16:39:19 +08:00
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def listener_maps(listeners) do
|
2019-01-22 18:53:49 +08:00
|
|
|
for listener(node: node, protocol: protocol, ip_address: interface, port: port) <- listeners do
|
2019-01-22 16:39:19 +08:00
|
|
|
# Listener options are left out intentionally: they can contain deeply nested values
|
|
|
|
|
# that are impossible to serialise to JSON.
|
|
|
|
|
#
|
|
|
|
|
# Management plugin/HTTP API had its fair share of bugs because of that
|
|
|
|
|
# and now filters out a lot of options. Raw listener data can be seen in
|
|
|
|
|
# rabbitmq-diagnostics status.
|
|
|
|
|
%{
|
|
|
|
|
node: node,
|
|
|
|
|
protocol: protocol,
|
2019-01-22 17:04:43 +08:00
|
|
|
interface: :inet.ntoa(interface) |> to_string |> maybe_enquote_interface,
|
2019-01-22 16:39:19 +08:00
|
|
|
port: port,
|
|
|
|
|
purpose: protocol_label(to_atom(protocol))
|
|
|
|
|
}
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def listener_rows(listeners) do
|
2019-01-22 18:53:49 +08:00
|
|
|
for listener(node: node, protocol: protocol, ip_address: interface, port: port) <- listeners do
|
2019-01-22 16:39:19 +08:00
|
|
|
# Listener options are left out intentionally, see above
|
|
|
|
|
[node: node,
|
|
|
|
|
protocol: protocol,
|
2019-01-22 17:04:43 +08:00
|
|
|
interface: :inet.ntoa(interface) |> to_string |> maybe_enquote_interface,
|
2019-01-22 18:53:49 +08:00
|
|
|
port: port,
|
2019-01-22 16:39:19 +08:00
|
|
|
purpose: protocol_label(to_atom(protocol))]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-01-23 22:45:37 +08:00
|
|
|
def normalize_protocol(proto) do
|
|
|
|
|
val = proto |> to_string |> String.downcase
|
|
|
|
|
case val do
|
|
|
|
|
"amqp091" -> "amqp"
|
|
|
|
|
"amqp0.9.1" -> "amqp"
|
|
|
|
|
"amqp0-9-1" -> "amqp"
|
|
|
|
|
"amqp0_9_1" -> "amqp"
|
|
|
|
|
|
|
|
|
|
"amqp10" -> "amqp"
|
|
|
|
|
"amqp1.0" -> "amqp"
|
|
|
|
|
"amqp1-0" -> "amqp"
|
|
|
|
|
"amqp1_0" -> "amqp"
|
|
|
|
|
|
|
|
|
|
"mqtt3.1" -> "mqtt"
|
|
|
|
|
"mqtt3.1.1" -> "mqtt"
|
|
|
|
|
"mqtt31" -> "mqtt"
|
|
|
|
|
"mqtt311" -> "mqtt"
|
|
|
|
|
"mqtt3_1" -> "mqtt"
|
|
|
|
|
"mqtt3_1_1" -> "mqtt"
|
|
|
|
|
|
|
|
|
|
"stomp1.0" -> "stomp"
|
|
|
|
|
"stomp1.1" -> "stomp"
|
|
|
|
|
"stomp1.2" -> "stomp"
|
|
|
|
|
"stomp10" -> "stomp"
|
|
|
|
|
"stomp11" -> "stomp"
|
|
|
|
|
"stomp12" -> "stomp"
|
|
|
|
|
"stomp1_0" -> "stomp"
|
|
|
|
|
"stomp1_1" -> "stomp"
|
|
|
|
|
"stomp1_2" -> "stomp"
|
|
|
|
|
|
|
|
|
|
"https" -> "http"
|
|
|
|
|
"http1" -> "http"
|
|
|
|
|
"http1.1" -> "http"
|
|
|
|
|
"http_api" -> "http"
|
|
|
|
|
"management" -> "http"
|
|
|
|
|
"management_ui" -> "http"
|
|
|
|
|
"ui" -> "http"
|
|
|
|
|
|
|
|
|
|
"cli" -> "clustering"
|
|
|
|
|
"distribution" -> "clustering"
|
|
|
|
|
|
|
|
|
|
"webmqtt" -> "http/web-mqtt"
|
|
|
|
|
"web-mqtt" -> "http/web-mqtt"
|
|
|
|
|
"web_mqtt" -> "http/web-mqtt"
|
|
|
|
|
|
|
|
|
|
"webstomp" -> "http/web-stomp"
|
|
|
|
|
"web-stomp" -> "http/web-stomp"
|
|
|
|
|
"web_stomp" -> "http/web-stomp"
|
|
|
|
|
|
|
|
|
|
_ -> val
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2019-01-22 12:43:25 +08:00
|
|
|
#
|
|
|
|
|
# Alarms
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
def alarm_lines(alarms, node_name) do
|
|
|
|
|
Enum.reduce(alarms, [],
|
|
|
|
|
fn
|
|
|
|
|
(:file_descriptor_limit, acc) ->
|
|
|
|
|
["File descriptor limit alarm on node #{node_name}" | acc]
|
|
|
|
|
({{:resource_limit, :memory, alarmed_node_name}, _}, acc) ->
|
|
|
|
|
["Memory alarm on node #{alarmed_node_name}" | acc]
|
|
|
|
|
({{:resource_limit, :disk, alarmed_node_name}, _}, acc) ->
|
|
|
|
|
["Free disk space alarm on node #{alarmed_node_name}" | acc]
|
|
|
|
|
end) |> Enum.reverse
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def local_alarms(alarms, node_name) do
|
|
|
|
|
Enum.filter(alarms,
|
|
|
|
|
fn
|
|
|
|
|
# local by definition
|
|
|
|
|
(:file_descriptor_limit) ->
|
|
|
|
|
true
|
|
|
|
|
({{:resource_limit, _, a_node}, _}) ->
|
|
|
|
|
node_name == a_node
|
|
|
|
|
end)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def clusterwide_alarms(alarms, node_name) do
|
|
|
|
|
alarms
|
|
|
|
|
|> Enum.reject(fn x -> x == :file_descriptor_limit end)
|
|
|
|
|
|> Enum.filter(fn ({{:resource_limit, _, a_node}, _}) ->
|
|
|
|
|
a_node != node_name
|
|
|
|
|
end)
|
|
|
|
|
end
|
2019-01-23 22:45:37 +08:00
|
|
|
|
2019-01-22 16:39:19 +08:00
|
|
|
#
|
|
|
|
|
# Implementation
|
|
|
|
|
#
|
|
|
|
|
|
2019-01-22 17:04:43 +08:00
|
|
|
defp maybe_enquote_interface(value) do
|
2019-01-22 16:39:19 +08:00
|
|
|
# This simplistic way of distinguishing IPv6 addresses,
|
|
|
|
|
# networks address ranges, etc actually works better
|
|
|
|
|
# for the kind of values we can get here than :inet functions. MK.
|
|
|
|
|
case value =~ ~r/:/ do
|
|
|
|
|
true -> "[#{value}]"
|
|
|
|
|
false -> value
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp protocol_label(:amqp), do: "AMQP 0-9-1 and AMQP 1.0"
|
|
|
|
|
defp protocol_label(:mqtt), do: "STOMP"
|
|
|
|
|
defp protocol_label(:stomp), do: "MQTT"
|
|
|
|
|
defp protocol_label(:http), do: "HTTP API"
|
|
|
|
|
defp protocol_label(:"http/web-mqtt"), do: "MQTT over WebSockets"
|
|
|
|
|
defp protocol_label(:"http/web-stomp"), do: "STOMP over WebSockets"
|
|
|
|
|
defp protocol_label(:clustering), do: "inter-node and CLI tool communication"
|
|
|
|
|
defp protocol_label(other), do: to_string(other)
|
2019-01-22 12:43:25 +08:00
|
|
|
|
2019-01-22 16:39:19 +08:00
|
|
|
end
|