Merge default

This commit is contained in:
Simon MacMullen 2012-10-16 17:44:32 +01:00
commit 59be413836
12 changed files with 277 additions and 44 deletions

View File

@ -33,7 +33,7 @@ import socket
LISTABLE = {'connections': False, 'channels': False, 'exchanges': True,
'queues': True, 'bindings': True, 'users': False,
'vhosts': False, 'permissions': False, 'nodes': False,
'parameters': False}
'parameters': False, 'policies': False}
SHOWABLE = {'overview': False}
@ -48,7 +48,8 @@ URIS = {
'vhost': '/vhosts/{name}',
'user': '/users/{name}',
'permission': '/permissions/{vhost}/{user}',
'parameter': '/parameters/{component}/{key}'
'parameter': '/parameters/{component}/{key}',
'policy': '/policies/{vhost}/{key}'
}
DECLARABLE = {
@ -69,7 +70,10 @@ DECLARABLE = {
'optional': {}},
'parameter': {'mandatory': ['component', 'key', 'value'],
'json': ['value'],
'optional': {}}
'optional': {}},
'policy': {'mandatory': ['vhost', 'key', 'pattern', 'definition'],
'json': ['definition', 'priority'],
'optional': {'priority' : 0}}
}
DELETABLE = {
@ -80,7 +84,8 @@ DELETABLE = {
'vhost': {'mandatory': ['name']},
'user': {'mandatory': ['name']},
'permission': {'mandatory': ['vhost', 'user']},
'parameter': {'mandatory': ['component', 'key']}
'parameter': {'mandatory': ['component', 'key']},
'policy': {'mandatory': ['vhost', 'key']}
}
CLOSABLE = {

View File

@ -535,6 +535,32 @@ or:
<td class="path">/api/parameters/<i>component</i>/<i>vhost</i>/<i>key</i></td>
<td>An individual parameter. To PUT a parameter, you will need a body looking something like this:
<pre>{"vhost": "/","component":"federation","key":"local_username","value":"guest"}</pre>
</td>
</tr>
<tr>
<td>X</td>
<td></td>
<td></td>
<td></td>
<td class="path">/api/policies</td>
<td>A list of all policies.</td>
</tr>
<tr>
<td>X</td>
<td></td>
<td></td>
<td></td>
<td class="path">/api/policies/<i>vhost</i></td>
<td>A list of all policies in a given virtual host.</td>
</tr>
<tr>
<td>X</td>
<td>X</td>
<td>X</td>
<td></td>
<td class="path">/api/policies/<i>vhost</i>/<i>key</i></td>
<td>An individual policy. To PUT a policy, you will need a body looking something like this:
<pre>{"pattern":"^amq.", "definition": {"federation-upstream-set":"all"}, "priority":0}</pre>
</td>
</tr>
<tr>

View File

@ -153,19 +153,19 @@ dispatcher_add(function(sammy) {
update();
return false;
});
path('#/policies', {'policies': '/parameters/policy',
path('#/policies', {'policies': '/policies',
'vhosts': '/vhosts'}, 'policies');
sammy.get('#/policies/:vhost/:id', function() {
render({'policy': '/parameters/policy/' + esc(this.params['vhost'])
render({'policy': '/policies/' + esc(this.params['vhost'])
+ '/' + esc(this.params['id'])},
'policy', '#/policies');
});
sammy.put('#/policies', function() {
put_parameter(this, ['key', 'pattern', 'policy'], ['priority'], []);
put_policy(this, ['key', 'pattern', 'policy'], ['priority'], []);
return false;
});
sammy.del('#/policies', function() {
if (sync_delete(this, '/parameters/:component/:vhost/:key'))
if (sync_delete(this, '/policies/:vhost/:key'))
go_to('#/policies');
return false;
});

View File

@ -818,6 +818,21 @@ function put_parameter(sammy, mandatory_keys, num_keys, bool_keys) {
if (sync_put(sammy, '/parameters/:component/:vhost/:key')) update();
}
function put_policy(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) {
delete sammy.params[i];
}
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';
}
}
if (sync_put(sammy, '/policies/:vhost/:key')) update();
}
function debug(str) {
$('<p>' + str + '</p>').appendTo('#debug');
@ -854,4 +869,4 @@ function xmlHttpRequest() {
});
}
});
})(jQuery);
})(jQuery);

View File

@ -10,25 +10,24 @@
<th>Virtual Host</th>
<% } %>
<th>Name</th>
<th>Regexp</th>
<th>Pattern</th>
<th>Definition</th>
<th>Priority</th>
<th>Policy</th>
</tr>
</thead>
<tbody>
<%
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];
for (var i = 0; i < policies.length; i++) {
var policy = 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['pattern']) %></td>
<td><%= fmt_string(policy.value['priority']) %></td>
<td><%= fmt_table_short(policy.value['policy']) %></td>
<td><%= fmt_string(policy.pattern) %></td>
<td><%= fmt_table_short(policy.definition) %></td>
<td><%= fmt_string(policy.priority) %></td>
</tr>
<% } %>
</tbody>
@ -44,7 +43,6 @@
<div class="hider">
<h3>
<form action="#/policies" method="put">
<input type="hidden" name="component" value="policy"/>
<table class="form">
<% if (vhosts_interesting) { %>
<tr>
@ -65,18 +63,18 @@
<td><input type="text" name="key"/><span class="mand">*</span></td>
</tr>
<tr>
<th><label>Regexp:</label></th>
<th><label>Pattern:</label></th>
<td><input type="text" name="pattern"/><span class="mand">*</span></td>
</tr>
<tr>
<th><label>Definition:</label></th>
<td><span class="multifield mand" id="definition"></span></td>
<td><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 mand" id="policy"></span></td>
<td><span class="mand">*</span></td>
</tr>
</table>
<input type="submit" value="Add policy"/>
</form>

View File

@ -9,16 +9,16 @@
<td><%= fmt_string(policy.vhost) %></td>
</tr>
<tr>
<th>Regexp</th>
<td><%= fmt_string(policy.value.pattern) %></td>
<th>Pattern</th>
<td><%= fmt_string(policy.pattern) %></td>
</tr>
<tr>
<th>Definition</th>
<td><%= fmt_table_short(policy.definition) %></td>
</tr>
<tr>
<th>Priority</th>
<td><%= fmt_string(policy.value.priority) %></td>
</tr>
<tr>
<th>Policy</th>
<td><%= fmt_table_short(policy.value.policy) %></td>
<td><%= fmt_string(policy.priority) %></td>
</tr>
</table>
</div>

View File

@ -46,6 +46,9 @@ dispatcher() ->
{["parameters", component], rabbit_mgmt_wm_parameters, []},
{["parameters", component, vhost], rabbit_mgmt_wm_parameters, []},
{["parameters", component, vhost, key], rabbit_mgmt_wm_parameter, []},
{["policies"], rabbit_mgmt_wm_policies, []},
{["policies", vhost], rabbit_mgmt_wm_policies, []},
{["policies", vhost, key], rabbit_mgmt_wm_policy, []},
{["connections"], rabbit_mgmt_wm_connections, []},
{["connections", connection], rabbit_mgmt_wm_connection, []},
{["connections", connection, "channels"], rabbit_mgmt_wm_connection_channels, []},

View File

@ -60,6 +60,7 @@ to_json(ReqData, Context) ->
[{rabbit_version, list_to_binary(Vsn)}] ++
filter(
[{parameters, rabbit_mgmt_wm_parameters:basic(ReqData)},
{policies, rabbit_mgmt_wm_policies:basic(ReqData)},
{users, rabbit_mgmt_wm_users:users()},
{vhosts, rabbit_mgmt_wm_vhosts:basic()},
{permissions, rabbit_mgmt_wm_permissions:permissions()},
@ -113,6 +114,7 @@ apply_defs(Body, SuccessFun, ErrorFun) ->
{ok, _, All} ->
try
for_all(parameters, All, fun add_parameter/1),
for_all(policies, All, fun add_policy/1),
for_all(users, All, fun add_user/1),
for_all(vhosts, All, fun add_vhost/1),
for_all(permissions, All, fun add_permission/1),
@ -156,6 +158,7 @@ export_name(_Name) -> true.
rw_state() ->
[{parameters, [vhost, component, key, value]},
{policies, [vhost, key, pattern, definition, priority]},
{users, [name, password_hash, tags]},
{vhosts, [name]},
{permissions, [user, vhost, configure, write, read]},
@ -202,6 +205,18 @@ add_parameter(Param) ->
exit(list_to_binary(E ++ S))
end.
add_policy(Param) ->
VHost = pget(vhost, Param),
Key = pget(key, Param),
case rabbit_policy:set(
VHost, Key, pget(pattern, Param),
rabbit_misc:json_to_term(pget(definition, Param)),
pget(priority, Param)) of
ok -> ok;
{error_string, E} -> S = rabbit_misc:format(" (~s/~s)", [VHost, Key]),
exit(list_to_binary(E ++ S))
end.
add_user(User) ->
rabbit_mgmt_wm_user:put_user(User).

View File

@ -0,0 +1,52 @@
%% 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_wm_policies).
-export([init/1, to_json/2, content_types_provided/2, is_authorized/2,
resource_exists/2, basic/1]).
-include("rabbit_mgmt.hrl").
-include_lib("webmachine/include/webmachine.hrl").
-include_lib("rabbit_common/include/rabbit.hrl").
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case basic(ReqData) of
not_found -> false;
_ -> true
end, ReqData, Context}.
to_json(ReqData, Context) ->
rabbit_mgmt_util:reply_list(basic(ReqData), ["priority"], ReqData, Context).
is_authorized(ReqData, Context) ->
rabbit_mgmt_util:is_authorized_admin(ReqData, Context).
%%--------------------------------------------------------------------
basic(ReqData) ->
case rabbit_mgmt_util:vhost(ReqData) of
not_found -> not_found;
none -> rabbit_policy:list();
VHost -> rabbit_policy:list(VHost)
end.

View File

@ -0,0 +1,87 @@
%% 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_wm_policy).
-export([init/1, resource_exists/2, to_json/2,
content_types_provided/2, content_types_accepted/2,
is_authorized/2, allowed_methods/2, accept_content/2,
delete_resource/2]).
-import(rabbit_misc, [pget/2]).
-include("rabbit_mgmt.hrl").
-include_lib("webmachine/include/webmachine.hrl").
-include_lib("rabbit_common/include/rabbit.hrl").
%%--------------------------------------------------------------------
init(_Config) -> {ok, #context{}}.
content_types_provided(ReqData, Context) ->
{[{"application/json", to_json}], ReqData, Context}.
content_types_accepted(ReqData, Context) ->
{[{"application/json", accept_content}], ReqData, Context}.
allowed_methods(ReqData, Context) ->
{['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}.
resource_exists(ReqData, Context) ->
{case policy(ReqData) of
not_found -> false;
_ -> true
end, ReqData, Context}.
to_json(ReqData, Context) ->
rabbit_mgmt_util:reply(policy(ReqData), ReqData, Context).
accept_content(ReqData, Context) ->
case rabbit_mgmt_util:vhost(ReqData) of
not_found ->
rabbit_mgmt_util:not_found(vhost_not_found, ReqData, Context);
VHost ->
rabbit_mgmt_util:with_decode(
[pattern, definition], ReqData, Context,
fun([Pattern, Definition], Body) ->
case rabbit_policy:set(
VHost, key(ReqData), Pattern,
rabbit_misc:json_to_term(Definition),
proplists:get_value(priority, Body)) of
ok ->
{true, ReqData, Context};
{error_string, Reason} ->
rabbit_mgmt_util:bad_request(
list_to_binary(Reason), ReqData, Context)
end
end)
end.
delete_resource(ReqData, Context) ->
ok = rabbit_policy:delete(
rabbit_mgmt_util:vhost(ReqData), key(ReqData)),
{true, ReqData, Context}.
is_authorized(ReqData, Context) ->
rabbit_mgmt_util:is_authorized_admin(ReqData, Context).
%%--------------------------------------------------------------------
policy(ReqData) ->
rabbit_policy:lookup(
rabbit_mgmt_util:vhost(ReqData), key(ReqData)).
key(ReqData) -> rabbit_mgmt_util:id(key, ReqData).

View File

@ -64,11 +64,9 @@ ha_test_() ->
{timeout, 60, fun ha/0}.
ha() ->
Policy = [{value, [{pattern, <<".*">>},
{policy, [{'ha-mode', <<"all">>}]
}]
}],
http_put("/parameters/policy/%2f/HA", Policy, ?NO_CONTENT),
Policy = [{pattern, <<".*">>},
{definition, [{'ha-mode', <<"all">>}]}],
http_put("/policies/%2f/HA", Policy, ?NO_CONTENT),
QArgs = [{node, <<"hare">>}],
http_put("/queues/%2f/ha-queue", QArgs, ?NO_CONTENT),
Q = wait_for("/queues/%2f/ha-queue"),

View File

@ -553,6 +553,7 @@ unicode_test() ->
ok.
definitions_test() ->
rabbit_runtime_parameters_test:register_policy_validator(),
XArgs = [{type, <<"direct">>}],
QArgs = [],
http_put("/queues/%2f/my-queue", QArgs, ?NO_CONTENT),
@ -576,13 +577,12 @@ definitions_test() ->
[{users, []},
{vhosts, []},
{permissions, []},
{parameters, [[{value, [{<<"pattern">>, <<".*">>},
{<<"priority">>, 1},
{<<"policy">>, [{<<"a">>, <<"b">>}]}
]},
{vhost, <<"/">>},
{component,<<"policy">>},
{key, <<"test">>}]]},
{policies, [[{vhost, <<"/">>},
{key, <<"test">>},
{pattern, <<".*">>},
{definition, [{testpos, [1, 2, 3]}]},
{priority, 1}
]]},
{queues, [[{name, <<"another-queue">>},
{vhost, <<"/">>},
{durable, true},
@ -607,7 +607,8 @@ definitions_test() ->
http_post("/definitions", ExtraConfig, ?CREATED),
http_post("/definitions", BrokenConfig, ?BAD_REQUEST),
http_delete("/queues/%2f/another-queue", ?NO_CONTENT),
http_delete("/parameters/policy/%2f/test", ?NO_CONTENT),
http_delete("/policies/%2f/test", ?NO_CONTENT),
rabbit_runtime_parameters_test:unregister_policy_validator(),
ok.
definitions_remove_things_test() ->
@ -935,6 +936,39 @@ parameters_test() ->
rabbit_runtime_parameters_test:unregister(),
ok.
policy_test() ->
rabbit_runtime_parameters_test:register_policy_validator(),
PolicyPos = [{vhost,<<"/">>},
{key,<<"policy_pos">>},
{pattern,<<".*">>},
{definition,[{testpos,[1,2,3]}]},
{priority,10}],
PolicyEven = [{vhost,<<"/">>},
{key,<<"policy_even">>},
{pattern,<<".*">>},
{definition,[{testeven,[1,2,3,4]}]},
{priority,10}],
http_put(
"/policies/%2f/policy_pos",
lists:keydelete(key, 1, PolicyPos),
?NO_CONTENT),
http_put(
"/policies/%2f/policy_even",
lists:keydelete(key, 1, PolicyEven),
?NO_CONTENT),
assert_item(PolicyPos, http_get("/policies/%2f/policy_pos", ?OK)),
assert_item(PolicyEven, http_get("/policies/%2f/policy_even", ?OK)),
List = [PolicyPos, PolicyEven],
assert_list(List, http_get("/policies", ?OK)),
assert_list(List, http_get("/policies/%2f", ?OK)),
http_delete("/policies/%2f/policy_pos", ?NO_CONTENT),
http_delete("/policies/%2f/policy_even", ?NO_CONTENT),
0 = length(http_get("/policies")),
0 = length(http_get("/policies/%2f")),
rabbit_runtime_parameters_test:unregister_policy_validator(),
ok.
%%---------------------------------------------------------------------------
msg(Key, Headers, Body) ->