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%% 7 8-module('Elixir.RabbitMQ.CLI.Ctl.Commands.ShovelStatusCommand'). 9 10-include("rabbit_shovel.hrl"). 11 12-behaviour('Elixir.RabbitMQ.CLI.CommandBehaviour'). 13 14-ignore_xref({'Elixir.RabbitMQ.CLI.DefaultOutput', output, 1}). 15 16-export([ 17 usage/0, 18 usage_doc_guides/0, 19 flags/0, 20 validate/2, 21 merge_defaults/2, 22 banner/2, 23 run/2, 24 switches/0, 25 aliases/0, 26 output/2, 27 scopes/0, 28 formatter/0, 29 help_section/0, 30 description/0 31 ]). 32 33 34%%---------------------------------------------------------------------------- 35%% Callbacks 36%%---------------------------------------------------------------------------- 37usage() -> 38 <<"shovel_status">>. 39 40usage_doc_guides() -> 41 [?SHOVEL_GUIDE_URL]. 42 43description() -> 44 <<"Displays status of Shovel on a node">>. 45 46help_section() -> 47 {plugin, shovel}. 48 49flags() -> 50 []. 51 52formatter() -> 53 'Elixir.RabbitMQ.CLI.Formatters.Table'. 54 55validate(_,_) -> 56 ok. 57 58merge_defaults(A,O) -> 59 {A, O}. 60 61banner(_, #{node := Node}) -> 62 erlang:iolist_to_binary([<<"Shovel status on node ">>, 63 atom_to_binary(Node, utf8)]). 64 65run(_Args, #{node := Node}) -> 66 case rabbit_misc:rpc_call(Node, rabbit_shovel_status, status, []) of 67 {badrpc, _} = Error -> 68 Error; 69 Status -> 70 {stream, Status} 71 end. 72 73switches() -> 74 []. 75 76aliases() -> 77 []. 78 79output({stream, ShovelStatus}, _Opts) -> 80 Formatted = [fmt_name(Name, 81 fmt_status(Status, 82 #{type => Type, 83 last_changed => fmt_ts(Timestamp)})) 84 || {Name, Type, Status, Timestamp} <- ShovelStatus], 85 {stream, Formatted}; 86output(E, _Opts) -> 87 'Elixir.RabbitMQ.CLI.DefaultOutput':output(E). 88 89scopes() -> 90 ['ctl', 'diagnostics']. 91 92%%---------------------------------------------------------------------------- 93%% Formatting 94%%---------------------------------------------------------------------------- 95fmt_name({Vhost, Name}, Map) -> 96 Map#{name => Name, vhost => Vhost}; 97fmt_name(Name, Map) -> 98 %% Static shovel names don't contain the vhost 99 Map#{name => Name}. 100 101fmt_ts({{YY, MM, DD}, {Hour, Min, Sec}}) -> 102 erlang:list_to_binary( 103 io_lib:format("~4..0w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", 104 [YY, MM, DD, Hour, Min, Sec])). 105 106fmt_status({'running' = St, Proplist}, Map) -> 107 maps:merge(Map#{state => St, 108 source_protocol => proplists:get_value(src_protocol, Proplist, 109 undefined), 110 source => proplists:get_value(src_uri, Proplist), 111 destination_protocol => proplists:get_value(dest_protocol, Proplist, undefined), 112 destination => proplists:get_value(dest_uri, Proplist), 113 termination_reason => <<>>}, details_to_map(Proplist)); 114fmt_status('starting' = St, Map) -> 115 Map#{state => St, 116 source => <<>>, 117 destination => <<>>, 118 termination_reason => <<>>}; 119fmt_status({'terminated' = St, Reason}, Map) -> 120 Map#{state => St, 121 termination_reason => list_to_binary(io_lib:format("~p", [Reason])), 122 source => <<>>, 123 destination => <<>>}. 124 125details_to_map(Proplist) -> 126 Keys = [{src_address, source_address}, {src_queue, source_queue}, 127 {src_exchange, source_exchange}, {src_exchange_key, source_exchange_key}, 128 {dest_address, destination_address}, {dest_queue, destination_queue}, 129 {dest_exchange, destination_exchange}, {dest_exchange_key, destination_exchange_key}], 130 maps:from_list([{New, proplists:get_value(Old, Proplist)} 131 || {Old, New} <- Keys, proplists:is_defined(Old, Proplist)]). 132