Merge bug24914
This commit is contained in:
commit
bd732b7494
|
|
@ -1,5 +1,5 @@
|
|||
body { font: 12px Verdana,sans-serif; color: #484848; padding: 8px 35px; }
|
||||
#logo { width: 204px; height: 37px; margin-bottom: 20px; background: url(../img/rabbitmqlogo.png); }
|
||||
#logo { margin-bottom: 20px; }
|
||||
#login-version { float: right; color: #444; }
|
||||
#login-version p { padding: 0 0 0.2em 0; margin: 0; text-align: right; }
|
||||
#login-version b { color: black; font-weight: normal; }
|
||||
|
|
@ -27,6 +27,9 @@ b, dt { color: black; font-weight: normal; }
|
|||
dd { margin-bottom: 5px; }
|
||||
div.box, div.section, div.section-hidden { overflow: auto; width: 100%; }
|
||||
|
||||
.left { float: left; }
|
||||
.right { float: right; }
|
||||
|
||||
.help { color: #888; cursor: pointer; }
|
||||
.help:hover { color: #444; }
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,11 @@
|
|||
<body>
|
||||
<div id="header">
|
||||
<div id="login-version"></div>
|
||||
<div id="logo"></div>
|
||||
<div id="logo">
|
||||
<a href="#/">
|
||||
<img src="img/rabbitmqlogo.png" width="204" height="37"/>
|
||||
</a>
|
||||
</div>
|
||||
<div id="menu">
|
||||
<p id="vhost-form">
|
||||
<label for="show-vhost">Virtual host: </label>
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ dispatcher_add(function(sammy) {
|
|||
'policy', '#/policies');
|
||||
});
|
||||
sammy.put('#/policies', function() {
|
||||
put_parameter(this, ['prefix'], []);
|
||||
put_parameter(this, ['key', 'pattern', 'policy'], ['priority'], []);
|
||||
return false;
|
||||
});
|
||||
sammy.del('#/policies', function() {
|
||||
|
|
|
|||
|
|
@ -415,6 +415,22 @@ function fmt_shortened_uri(uri0) {
|
|||
}
|
||||
}
|
||||
|
||||
function fmt_client_name(properties) {
|
||||
var res = [];
|
||||
if (properties.product != undefined) {
|
||||
res.push(properties.product);
|
||||
}
|
||||
if (properties.platform != undefined) {
|
||||
res.push(properties.platform);
|
||||
}
|
||||
res = res.join(" / ");
|
||||
|
||||
if (properties.version != undefined) {
|
||||
res += '<sub>' + properties.version + '</sub>';
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function alt_rows(i) {
|
||||
return (i % 2 == 0) ? ' class="alt1"' : ' class="alt2"';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,7 +135,11 @@ HELP = {
|
|||
User can do everything monitoring can do, manage users, \
|
||||
vhosts and permissions, and close other user\'s connections. \
|
||||
</dd> \
|
||||
</dl>',
|
||||
</dl> \
|
||||
<p> \
|
||||
Note that you can set any tag here; the links for the above three \
|
||||
tags are just for convenience. \
|
||||
</p>',
|
||||
|
||||
'queued-messages':
|
||||
'Total messages in all queues:\
|
||||
|
|
@ -177,6 +181,8 @@ HELP = {
|
|||
|
||||
'disk-monitoring-no-watermark' : 'There is no disk space low watermark set. RabbitMQ will not take any action to avoid running out of disk space.',
|
||||
|
||||
'resource-counts' : 'Shows total number of objects for all virtual hosts the current user has access to.',
|
||||
|
||||
'foo': 'foo' // No comma.
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -778,7 +778,7 @@ function maybe_remove_fields(params) {
|
|||
return params;
|
||||
}
|
||||
|
||||
function put_parameter(sammy, mandatory_keys, num_keys) {
|
||||
function put_parameter(sammy, mandatory_keys, num_keys, bool_keys) {
|
||||
for (var i in sammy.params) {
|
||||
if (i === 'length' || !sammy.params.hasOwnProperty(i)) continue;
|
||||
if (sammy.params[i] == '' && mandatory_keys.indexOf(i) == -1) {
|
||||
|
|
@ -787,6 +787,9 @@ function put_parameter(sammy, mandatory_keys, num_keys) {
|
|||
else if (num_keys.indexOf(i) != -1) {
|
||||
sammy.params[i] = parseInt(sammy.params[i]);
|
||||
}
|
||||
else if (bool_keys.indexOf(i) != -1) {
|
||||
sammy.params[i] = sammy.params[i] == 'true';
|
||||
}
|
||||
}
|
||||
var params = {"component": sammy.params.component,
|
||||
"vhost": sammy.params.vhost,
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@
|
|||
<table class="list">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="<% if (nodes_interesting) { %>6<% } else { %>5<% } %>">Network</th>
|
||||
<th colspan="<% if (nodes_interesting) { %>7<% } else { %>6<% } %>">Network</th>
|
||||
<th colspan="<% if (vhosts_interesting) { %>5<% } else { %>4<% } %>">Overview</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><%= fmt_sort('Protocol', 'protocol') %></th>
|
||||
<th><%= fmt_sort('Name', 'name') %></th>
|
||||
<th><%= fmt_sort('Protocol', 'protocol') %></th>
|
||||
<th><%= fmt_sort('Client', 'properties') %></th>
|
||||
<% if (nodes_interesting) { %>
|
||||
<th><%= fmt_sort('Node', 'node') %></th>
|
||||
<% } %>
|
||||
|
|
@ -31,13 +32,14 @@
|
|||
var connection = connections[i];
|
||||
%>
|
||||
<tr<%= alt_rows(i)%>>
|
||||
<td><%= link_conn(connection.name) %></td>
|
||||
<td>
|
||||
<%= connection.protocol %>
|
||||
<% if (connection.ssl) { %>
|
||||
<sub>SSL</sub>
|
||||
<% } %>
|
||||
</td>
|
||||
<td><%= link_conn(connection.name) %></td>
|
||||
<td><%= fmt_client_name(connection.client_properties) %></td>
|
||||
<% if (nodes_interesting) { %>
|
||||
<td><%= connection.node %></td>
|
||||
<% } %>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<h2>Totals</h2>
|
||||
<div class="hider updatable">
|
||||
<% if (overview.statistics_db_node != 'not_running') { %>
|
||||
<div class="left">
|
||||
<h3>Queued messages <span class="help" id="queued-messages"></span></h3>
|
||||
<div class="box">
|
||||
<%= queue_length(overview.queue_totals, 'Ready', 'messages_ready') %>
|
||||
|
|
@ -18,6 +19,39 @@
|
|||
<% } else { %>
|
||||
Totals not available
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<div class="right">
|
||||
<h3>Global counts <span class="help" id="resource-counts"></span></h3>
|
||||
<table class="list">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Count</th>
|
||||
</tr>
|
||||
<tr class="alt1">
|
||||
<td class="r">Connections</td>
|
||||
<td class="c"><%= overview.object_totals.connections %></td>
|
||||
</tr>
|
||||
<tr class="alt2">
|
||||
<td class="r">Channels</td>
|
||||
<td class="c"><%= overview.object_totals.channels %></td>
|
||||
</tr>
|
||||
<tr class="alt1">
|
||||
<td class="r">Exchanges</td>
|
||||
<td class="c"><%= overview.object_totals.exchanges %></td>
|
||||
</tr>
|
||||
<tr class="alt2">
|
||||
<td class="r">Queues</td>
|
||||
<td class="c"><%= overview.object_totals.queues %></td>
|
||||
</tr>
|
||||
<% if (overview.object_totals['consumers'] != undefined) { %> <tr>
|
||||
<tr class="alt1">
|
||||
<td class="r">Consumers</td>
|
||||
<td class="c"><%= overview.object_totals.consumers %></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,21 +10,24 @@
|
|||
<th>Virtual Host</th>
|
||||
<% } %>
|
||||
<th>Name</th>
|
||||
<th>Prefix</th>
|
||||
<th>Regexp</th>
|
||||
<th>Priority</th>
|
||||
<th>Policy</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
for (var i = 0; i < policies.length; i++) {
|
||||
var policy = policies[i];
|
||||
var sorted_policies = policies.sort(function(a,b) {return b.value['priority'] || 0 - a.value['priority'] || 0} );
|
||||
for (var i = 0; i < sorted_policies.length; i++) {
|
||||
var policy = sorted_policies[i];
|
||||
%>
|
||||
<tr<%= alt_rows(i)%>>
|
||||
<% if (vhosts_interesting) { %>
|
||||
<td><%= fmt_string(policy.vhost) %></td>
|
||||
<% } %>
|
||||
<td><%= link_policy(policy.vhost, policy.key) %></td>
|
||||
<td><%= fmt_string(policy.value['prefix']) %></td>
|
||||
<td><%= fmt_string(policy.value['pattern']) %></td>
|
||||
<td><%= fmt_string(policy.value['priority']) %></td>
|
||||
<td><%= fmt_table_short(policy.value['policy']) %></td>
|
||||
</tr>
|
||||
<% } %>
|
||||
|
|
@ -62,12 +65,17 @@
|
|||
<td><input type="text" name="key"/><span class="mand">*</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label>Prefix:</label></th>
|
||||
<td><input type="text" name="prefix"/></td>
|
||||
<th><label>Regexp:</label></th>
|
||||
<td><input type="text" name="pattern"/><span class="mand">*</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label>Priority:</label></th>
|
||||
<td><input type="text" name="priority"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><label>Policy:</label></th>
|
||||
<td><span class="multifield" id="policy"></span></td>
|
||||
<td><span class="multifield mand" id="policy"></span></td>
|
||||
<td><span class="mand">*</span></td>
|
||||
</tr>
|
||||
</table>
|
||||
<input type="submit" value="Add policy"/>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,12 @@
|
|||
<td><%= fmt_string(policy.vhost) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Prefix</th>
|
||||
<td><%= fmt_string(policy.value.prefix) %></td>
|
||||
<th>Regexp</th>
|
||||
<td><%= fmt_string(policy.value.pattern) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Priority</th>
|
||||
<td><%= fmt_string(policy.value.priority) %></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Policy</th>
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ start_link() ->
|
|||
%% mirrored_supervisor to maintain the uniqueness of this process.
|
||||
case gen_server2:start_link(?MODULE, [], []) of
|
||||
{ok, Pid} -> yes = global:re_register_name(?MODULE, Pid),
|
||||
rabbit:force_event_refresh(),
|
||||
{ok, Pid};
|
||||
Else -> Else
|
||||
end.
|
||||
|
|
@ -213,7 +214,6 @@ init([]) ->
|
|||
%% When Rabbit is overloaded, it's usually especially important
|
||||
%% that the management plugin work.
|
||||
process_flag(priority, high),
|
||||
rabbit:force_event_refresh(),
|
||||
{ok, Interval} = application:get_env(rabbit, collect_statistics_interval),
|
||||
rabbit_log:info("Statistics database started.~n"),
|
||||
{ok, #state{interval = Interval,
|
||||
|
|
@ -272,7 +272,8 @@ handle_call({get_overview, User}, _From, State = #state{tables = Tables}) ->
|
|||
Qs0 = [rabbit_mgmt_format:queue(Q) || V <- VHosts,
|
||||
Q <- rabbit_amqqueue:list(V)],
|
||||
Qs1 = basic_queue_stats(Qs0, State),
|
||||
Totals = sum(Qs1, ?OVERVIEW_QUEUE_STATS),
|
||||
QueueTotals = sum(Qs1, ?OVERVIEW_QUEUE_STATS),
|
||||
|
||||
Filter = fun(Id, Name) ->
|
||||
lists:member(pget(vhost, pget(Name, Id)), VHosts)
|
||||
end,
|
||||
|
|
@ -285,8 +286,27 @@ handle_call({get_overview, User}, _From, State = #state{tables = Tables}) ->
|
|||
end,
|
||||
Publish = F(channel_exchange_stats, exchange),
|
||||
Consume = F(channel_queue_stats, queue_details),
|
||||
|
||||
F2 = case User of
|
||||
all -> fun (L) -> length(L) end;
|
||||
_ -> fun (L) -> length(rabbit_mgmt_util:filter_user(L, User)) end
|
||||
end,
|
||||
%% Filtering out the user's consumers would be rather expensive so let's
|
||||
%% just not show it
|
||||
Consumers = case User of
|
||||
all -> [{consumers,
|
||||
ets:info(orddict:fetch(consumers, Tables), size)}];
|
||||
_ -> []
|
||||
end,
|
||||
ObjectTotals = Consumers ++
|
||||
[{queues, length(Qs0)},
|
||||
{exchanges, length([X || V <- VHosts,
|
||||
X <- rabbit_exchange:list(V)])},
|
||||
{connections, F2(created_events(connection_stats, Tables))},
|
||||
{channels, F2(created_events(channel_stats, Tables))}],
|
||||
reply([{message_stats, Publish ++ Consume},
|
||||
{queue_totals, Totals}], State);
|
||||
{queue_totals, QueueTotals},
|
||||
{object_totals, ObjectTotals}], State);
|
||||
|
||||
handle_call(_Request, _From, State) ->
|
||||
reply(not_understood, State).
|
||||
|
|
@ -377,7 +397,7 @@ handle_event(#event{type = consumer_deleted, props = Props}, State) ->
|
|||
Props, State);
|
||||
|
||||
handle_event(#event{type = queue_mirror_deaths, props = Props},
|
||||
State = #state{tables = Tables}) ->
|
||||
#state{tables = Tables}) ->
|
||||
Dead = pget(pids, Props),
|
||||
Table = orddict:fetch(queue_stats, Tables),
|
||||
%% Only the master can be in the DB, but it's easier just to
|
||||
|
|
@ -422,10 +442,8 @@ handle_stats(TName, Stats0, Timestamp, Funs,
|
|||
handle_deleted(TName, #event{props = Props}, State = #state{tables = Tables}) ->
|
||||
Table = orddict:fetch(TName, Tables),
|
||||
Pid = pget(pid, Props),
|
||||
Name = pget(name, Props),
|
||||
ets:delete(Table, {id(Pid), create}),
|
||||
ets:delete(Table, {id(Pid), stats}),
|
||||
ets:delete(Table, {Name, synchronised_slaves}),
|
||||
{ok, State}.
|
||||
|
||||
handle_consumer(Fun, Props,
|
||||
|
|
@ -560,18 +578,6 @@ consumer_details_fun(PatternFun, State = #state{tables = Tables}) ->
|
|||
ets:match(Table, {Pattern, '$1'}))]}]
|
||||
end.
|
||||
|
||||
synchronised_slaves_fun(#state{tables = Tables}) ->
|
||||
Table = orddict:fetch(queue_stats, Tables),
|
||||
|
||||
fun (Props) -> QName = rabbit_misc:r(pget(vhost, Props), queue,
|
||||
pget(name, Props)),
|
||||
Key = {QName, synchronised_slaves},
|
||||
case ets:lookup(Table, Key) of
|
||||
[] -> [];
|
||||
[{_, N}] -> [{synchronised_slave_nodes, N}]
|
||||
end
|
||||
end.
|
||||
|
||||
zero_old_rates(Stats, State) -> [maybe_zero_rate(S, State) || S <- Stats].
|
||||
|
||||
maybe_zero_rate({Key, Val}, #state{interval = Interval}) ->
|
||||
|
|
@ -659,8 +665,7 @@ detail_queue_stats(Objs, State) ->
|
|||
queue_funs(State))).
|
||||
|
||||
queue_funs(State) ->
|
||||
[basic_stats_fun(queue_stats, pid, State), augment_msg_stats_fun(State),
|
||||
synchronised_slaves_fun(State)].
|
||||
[basic_stats_fun(queue_stats, pid, State), augment_msg_stats_fun(State)].
|
||||
|
||||
exchange_stats(Objs, FineSpecs, State) ->
|
||||
merge_stats(Objs, [fine_stats_fun(FineSpecs, State),
|
||||
|
|
|
|||
|
|
@ -104,16 +104,7 @@ utf8_safe(V) ->
|
|||
<<"Invalid UTF-8, base64 is: ", Enc/binary>>
|
||||
end.
|
||||
|
||||
parameter(P) -> pset(value, param0(pget(value, P)), P).
|
||||
|
||||
param0(L = [{_, _} | _]) -> {struct, [{K, param0(V)} || {K, V} <- L]};
|
||||
param0(L) when is_list(L) -> [param0(I) || I <- L];
|
||||
param0(B) when is_binary(B) -> B;
|
||||
param0(N) when is_number(N) -> N;
|
||||
param0(null) -> null;
|
||||
param0(true) -> true;
|
||||
param0(false) -> false.
|
||||
|
||||
parameter(P) -> pset(value, rabbit_misc:term_to_json(pget(value, P)), P).
|
||||
|
||||
tuple(unknown) -> unknown;
|
||||
tuple(Tuple) when is_tuple(Tuple) -> [tuple(E) || E <- tuple_to_list(Tuple)];
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
%% 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 Management Plugin.
|
||||
%%
|
||||
%% The Initial Developer of the Original Code is VMware, Inc.
|
||||
%% Copyright (c) 2010-2012 VMware, Inc. All rights reserved.
|
||||
%%
|
||||
|
||||
-module(rabbit_mgmt_parse).
|
||||
|
||||
-export([parameter_value/1]).
|
||||
|
||||
%% TODO there is a bunch of stuff in format / util that should be moved here.
|
||||
%% The idea is format means to JSON, this module means from JSON
|
||||
|
||||
parameter_value({struct, Props}) ->
|
||||
[{K, parameter_value(V)} || {K, V} <- Props];
|
||||
|
||||
parameter_value(L) when is_list(L) ->
|
||||
[parameter_value(V) || V <- L];
|
||||
|
||||
parameter_value(N) when is_number(N) -> N;
|
||||
parameter_value(B) when is_binary(B) -> B;
|
||||
parameter_value(null) -> null;
|
||||
parameter_value(true) -> true;
|
||||
parameter_value(false) -> false.
|
||||
|
|
@ -27,8 +27,8 @@
|
|||
-export([with_channel/4, with_channel/5]).
|
||||
-export([props_to_method/2, props_to_method/4]).
|
||||
-export([all_or_one_vhost/2, http_to_amqp/5, reply/3, filter_vhost/3]).
|
||||
-export([filter_conn_ch_list/3, with_decode/5, decode/1, decode/2, redirect/2,
|
||||
args/1]).
|
||||
-export([filter_conn_ch_list/3, filter_user/2]).
|
||||
-export([with_decode/5, decode/1, decode/2, redirect/2, args/1]).
|
||||
-export([reply_list/3, reply_list/4, sort_list/2, destination_type/1]).
|
||||
-export([post_respond/1, columns/1, want_column/2, is_monitor/1]).
|
||||
-export([list_visible_vhosts/1, b64decode_or_throw/1]).
|
||||
|
|
@ -388,8 +388,10 @@ filter_vhost(List, _ReqData, Context) ->
|
|||
VHosts = list_login_vhosts(Context#context.user),
|
||||
[I || I <- List, lists:member(pget(vhost, I), VHosts)].
|
||||
|
||||
filter_user(List, _ReqData,
|
||||
#context{user = #user{username = Username, tags = Tags}}) ->
|
||||
filter_user(List, _ReqData, #context{user = User}) ->
|
||||
filter_user(List, User).
|
||||
|
||||
filter_user(List, #user{username = Username, tags = Tags}) ->
|
||||
case is_monitor(Tags) of
|
||||
true -> List;
|
||||
false -> [I || I <- List, pget(user, I) == Username]
|
||||
|
|
|
|||
|
|
@ -195,8 +195,7 @@ add_parameter(Param) ->
|
|||
Comp = pget(component, Param),
|
||||
Key = pget(key, Param),
|
||||
case rabbit_runtime_parameters:set(
|
||||
VHost, Comp, Key,
|
||||
rabbit_mgmt_parse:parameter_value(pget(value, Param))) of
|
||||
VHost, Comp, Key, rabbit_misc:json_to_term(pget(value, Param))) of
|
||||
ok -> ok;
|
||||
{error_string, E} -> S = rabbit_misc:format(" (~s/~s/~s)",
|
||||
[VHost, Comp, Key]),
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ accept_content(ReqData, Context) ->
|
|||
fun([Value], _) ->
|
||||
case rabbit_runtime_parameters:set(
|
||||
VHost, component(ReqData), key(ReqData),
|
||||
rabbit_mgmt_parse:parameter_value(Value)) of
|
||||
rabbit_misc:json_to_term(Value)) of
|
||||
ok ->
|
||||
{true, ReqData, Context};
|
||||
{error_string, Reason} ->
|
||||
|
|
|
|||
|
|
@ -576,7 +576,8 @@ definitions_test() ->
|
|||
[{users, []},
|
||||
{vhosts, []},
|
||||
{permissions, []},
|
||||
{parameters, [[{value, [{<<"prefix">>, <<"">>},
|
||||
{parameters, [[{value, [{<<"pattern">>, <<".*">>},
|
||||
{<<"priority">>, 1},
|
||||
{<<"policy">>, [{<<"a">>, <<"b">>}]}
|
||||
]},
|
||||
{vhost, <<"/">>},
|
||||
|
|
|
|||
Loading…
Reference in New Issue