Merge branch 'stable'

This commit is contained in:
Luke Bakken 2017-10-30 17:59:00 -07:00
commit dffde95b82
6 changed files with 201 additions and 131 deletions

View File

@ -18,7 +18,7 @@
</p>
<p>
To use it, <a href="/cli/rabbitmqadmin">download it</a> from this node (right click,
To use it, <a href="rabbitmqadmin">download it</a> from this node (right click,
Save As), make sure it is executable, and drop it in your <code>PATH</code>. Note that
many browsers will rename the
file <code>rabbitmqadmin.txt</code>. <code>rabbitmqadmin</code> requires Python

View File

@ -22,18 +22,43 @@
-export([dispatcher/0, web_ui/0]).
build_dispatcher(Ignore) ->
Routes = build_routes(Ignore),
cowboy_router:compile(Routes).
build_routes(Ignore) ->
ManagementApp = module_app(?MODULE),
Prefix = rabbit_mgmt_util:get_path_prefix(),
RootIdxRtes = build_root_index_routes(Prefix, ManagementApp),
ApiIdxRte = {"/api", cowboy_static, {priv_file, ManagementApp, "www/api/index.html"}},
CliIdxRte = {"/cli", cowboy_static, {priv_file, ManagementApp, "www/cli/index.html"}},
MgmtRdrRte = {"/mgmt", rabbit_mgmt_wm_redirect, "/"},
LocalPaths = [{module_app(M), "www"} || M <- modules(Ignore)],
cowboy_router:compile([{'_',
[{"/api" ++ Path, Mod, Args}
|| {Path, Mod, Args} <- lists:append([Module:dispatcher()
|| Module <- modules(Ignore)])]
++ [{"/", cowboy_static, {priv_file, ManagementApp, "www/index.html"}},
{"/api", cowboy_static, {priv_file, ManagementApp, "www/api/index.html"}},
{"/cli", cowboy_static, {priv_file, ManagementApp, "www/cli/index.html"}},
{"/mgmt", rabbit_mgmt_wm_redirect, "/"}]
++ [{"/[...]", rabbit_mgmt_wm_static, LocalPaths}]
}]).
LocalStaticRte = {"/[...]", rabbit_mgmt_wm_static, LocalPaths},
% NB: order is significant in the routing list
Routes0 = build_module_routes(Ignore) ++
[ApiIdxRte, CliIdxRte, MgmtRdrRte, LocalStaticRte],
Routes1 = maybe_add_path_prefix(Routes0, Prefix),
% NB: ensure the root routes are first
Routes2 = RootIdxRtes ++ Routes1,
[{'_', Routes2}].
build_root_index_routes("", ManagementApp) ->
[{"/", cowboy_static, root_idx_file(ManagementApp)}];
build_root_index_routes(Prefix, ManagementApp) ->
[{"/", rabbit_mgmt_wm_redirect, Prefix ++ "/"},
{Prefix, cowboy_static, root_idx_file(ManagementApp)}].
root_idx_file(ManagementApp) ->
{priv_file, ManagementApp, "www/index.html"}.
maybe_add_path_prefix(Routes, "") ->
Routes;
maybe_add_path_prefix(Routes, Prefix) ->
[{Prefix ++ Path, Mod, Args} || {Path, Mod, Args} <- Routes].
build_module_routes(Ignore) ->
Routes = [Module:dispatcher() || Module <- modules(Ignore)],
[{"/api" ++ Path, Mod, Args} || {Path, Mod, Args} <- lists:append(Routes)].
modules(IgnoreApps) ->
[Module || {App, Module, Behaviours} <-

View File

@ -48,6 +48,7 @@
]).
-export([direct_request/6]).
-export([qs_val/2]).
-export([get_path_prefix/0]).
-import(rabbit_misc, [pget/2]).
@ -427,6 +428,19 @@ get_data({paged, Data}) ->
get_data({_, Data}) ->
Data.
get_path_prefix() ->
EnvPrefix = rabbit_misc:get_env(rabbitmq_management, path_prefix, ""),
fixup_prefix(EnvPrefix).
fixup_prefix("") ->
"";
fixup_prefix([Char|_Rest]=EnvPrefix) when is_list(EnvPrefix), Char =:= $/ ->
EnvPrefix;
fixup_prefix(EnvPrefix) when is_list(EnvPrefix) ->
"/" ++ EnvPrefix;
fixup_prefix(EnvPrefix) when is_binary(EnvPrefix) ->
fixup_prefix(rabbit_data_coercion:to_list(EnvPrefix)).
%% XXX sort_list_and_paginate/2 is a more proper name for this function, keeping it
%% with this name for backwards compatibility
-spec sort_list([Fact], [string()]) -> [Fact] when

View File

@ -93,13 +93,14 @@ accept_content(ReqData0, {_Mode, Context}) ->
{stop, _, _} = Res ->
Res;
{true, ReqData, Context2} ->
Loc = rabbit_web_dispatch_util:relativise(
binary_to_list(cowboy_req:path(ReqData)),
binary_to_list(
rabbit_mgmt_format:url(
"/api/bindings/~s/e/~s/~s/~s/~s",
[VHost, Source, DestType, Dest,
rabbit_mgmt_format:pack_binding_props(Key, Args)]))),
From = binary_to_list(cowboy_req:path(ReqData)),
Prefix = rabbit_mgmt_util:get_path_prefix(),
BindingProps = rabbit_mgmt_format:pack_binding_props(Key, Args),
UrlWithBindings = rabbit_mgmt_format:url("/api/bindings/~s/e/~s/~s/~s/~s",
[VHost, Source, DestType,
Dest, BindingProps]),
To = Prefix ++ binary_to_list(UrlWithBindings),
Loc = rabbit_web_dispatch_util:relativise(From, To),
{{true, Loc}, ReqData, Context2}
end.

View File

@ -38,101 +38,101 @@
-import(rabbit_misc, [pget/2]).
-define(COLLECT_INTERVAL, 1000).
-define(PATH_PREFIX, "/custom-prefix").
-compile(export_all).
all() ->
[
{group, non_parallel_tests}
{group, all_tests_with_prefix},
{group, all_tests_without_prefix}
].
groups() ->
[
{non_parallel_tests, [], [
overview_test,
auth_test,
cluster_name_test,
nodes_test,
memory_test,
ets_tables_memory_test,
vhosts_test,
vhosts_trace_test,
users_test,
without_permissions_users_test,
users_bulk_delete_test,
users_legacy_administrator_test,
adding_a_user_with_password_test,
adding_a_user_with_password_hash_test,
adding_a_user_with_permissions_in_single_operation_test,
adding_a_user_without_tags_fails_test,
adding_a_user_without_password_or_hash_test,
adding_a_user_with_both_password_and_hash_fails_test,
updating_a_user_without_password_or_hash_clears_password_test,
user_credential_validation_accept_everything_succeeds_test,
user_credential_validation_min_length_succeeds_test,
user_credential_validation_min_length_fails_test,
permissions_validation_test,
permissions_list_test,
permissions_test,
topic_permissions_list_test,
topic_permissions_test,
connections_test,
multiple_invalid_connections_test,
exchanges_test,
queues_test,
queues_well_formed_json_test,
bindings_test,
bindings_post_test,
bindings_e2e_test,
permissions_administrator_test,
permissions_vhost_test,
permissions_amqp_test,
permissions_connection_channel_consumer_test,
consumers_test,
definitions_test,
definitions_vhost_test,
definitions_password_test,
definitions_remove_things_test,
definitions_server_named_queue_test,
aliveness_test,
healthchecks_test,
arguments_test,
arguments_table_test,
queue_purge_test,
queue_actions_test,
exclusive_consumer_test,
exclusive_queue_test,
connections_channels_pagination_test,
exchanges_pagination_test,
exchanges_pagination_permissions_test,
queue_pagination_test,
queue_pagination_columns_test,
queues_pagination_permissions_test,
samples_range_test,
sorting_test,
format_output_test,
columns_test,
get_test,
get_fail_test,
publish_test,
publish_accept_json_test,
publish_fail_test,
publish_base64_test,
publish_unrouted_test,
if_empty_unused_test,
parameters_test,
global_parameters_test,
policy_test,
policy_permissions_test,
issue67_test,
extensions_test,
cors_test,
vhost_limits_list_test,
vhost_limit_set_test,
rates_test
]}
{all_tests_with_prefix, [], all_tests()},
{all_tests_without_prefix, [], all_tests()}
].
all_tests() -> [
overview_test,
auth_test,
cluster_name_test,
nodes_test,
memory_test,
ets_tables_memory_test,
vhosts_test,
vhosts_trace_test,
users_test,
users_legacy_administrator_test,
adding_a_user_with_password_test,
adding_a_user_with_password_hash_test,
adding_a_user_with_permissions_in_single_operation_test,
adding_a_user_without_tags_fails_test,
adding_a_user_without_password_or_hash_test,
adding_a_user_with_both_password_and_hash_fails_test,
updating_a_user_without_password_or_hash_clears_password_test,
user_credential_validation_accept_everything_succeeds_test,
user_credential_validation_min_length_succeeds_test,
user_credential_validation_min_length_fails_test,
permissions_validation_test,
permissions_list_test,
permissions_test,
connections_test,
multiple_invalid_connections_test,
exchanges_test,
queues_test,
queues_well_formed_json_test,
bindings_test,
bindings_post_test,
bindings_e2e_test,
permissions_administrator_test,
permissions_vhost_test,
permissions_amqp_test,
permissions_connection_channel_consumer_test,
consumers_test,
definitions_test,
definitions_vhost_test,
definitions_password_test,
definitions_remove_things_test,
definitions_server_named_queue_test,
aliveness_test,
healthchecks_test,
arguments_test,
arguments_table_test,
queue_purge_test,
queue_actions_test,
exclusive_consumer_test,
exclusive_queue_test,
connections_channels_pagination_test,
exchanges_pagination_test,
exchanges_pagination_permissions_test,
queue_pagination_test,
queue_pagination_columns_test,
queues_pagination_permissions_test,
samples_range_test,
sorting_test,
format_output_test,
columns_test,
get_test,
get_fail_test,
publish_test,
publish_accept_json_test,
publish_fail_test,
publish_base64_test,
publish_unrouted_test,
if_empty_unused_test,
parameters_test,
global_parameters_test,
policy_test,
policy_permissions_test,
issue67_test,
extensions_test,
cors_test,
vhost_limits_list_test,
vhost_limit_set_test,
rates_test].
%% -------------------------------------------------------------------
%% Testsuite setup/teardown.
%% -------------------------------------------------------------------
@ -146,28 +146,37 @@ merge_app_env(Config) ->
{sample_retention_policies,
[{global, [{605, 1}]},
{basic, [{605, 1}]},
{detailed, [{10, 1}]}] }]}).
{detailed, [{10, 1}]}]
}]}).
init_per_suite(Config) ->
start_broker(Config) ->
Setup0 = rabbit_ct_broker_helpers:setup_steps(),
Setup1 = rabbit_ct_client_helpers:setup_steps(),
Steps = Setup0 ++ Setup1,
rabbit_ct_helpers:run_setup_steps(Config, Steps).
finish_init(Group, Config) ->
rabbit_ct_helpers:log_environment(),
inets:start(),
Config1 = rabbit_ct_helpers:set_config(Config, [
{rmq_nodename_suffix, ?MODULE}
]),
Config2 = merge_app_env(Config1),
rabbit_ct_helpers:run_setup_steps(Config2,
rabbit_ct_broker_helpers:setup_steps() ++
rabbit_ct_client_helpers:setup_steps()).
end_per_suite(Config) ->
rabbit_ct_helpers:run_teardown_steps(Config,
rabbit_ct_client_helpers:teardown_steps() ++
rabbit_ct_broker_helpers:teardown_steps()).
NodeConf = [{rmq_nodename_suffix, Group}],
Config1 = rabbit_ct_helpers:set_config(Config, NodeConf),
merge_app_env(Config1).
init_per_group(_, Config) ->
Config.
init_per_group(all_tests_with_prefix=Group, Config0) ->
PathConfig = {rabbitmq_management, [{path_prefix, ?PATH_PREFIX}]},
Config1 = rabbit_ct_helpers:merge_app_env(Config0, PathConfig),
Config2 = finish_init(Group, Config1),
start_broker(Config2);
init_per_group(Group, Config0) ->
Config1 = finish_init(Group, Config0),
start_broker(Config1).
end_per_group(_, Config) ->
Config.
inets:stop(),
Teardown0 = rabbit_ct_client_helpers:teardown_steps(),
Teardown1 = rabbit_ct_broker_helpers:teardown_steps(),
Steps = Teardown0 ++ Teardown1,
rabbit_ct_helpers:run_teardown_steps(Config, Steps).
init_per_testcase(Testcase, Config) ->
rabbit_ct_helpers:testcase_started(Config, Testcase).
@ -200,7 +209,6 @@ end_per_testcase0(_, Config) -> Config.
%% Testcases.
%% -------------------------------------------------------------------
overview_test(Config) ->
%% Rather crude, but this req doesn't say much and at least this means it
%% didn't blow up.
@ -209,7 +217,6 @@ overview_test(Config) ->
{tags, <<"management">>}], {group, '2xx'}),
http_get(Config, "/overview", "myuser", "myuser", ?OK),
http_delete(Config, "/users/myuser", {group, '2xx'}),
passed.
cluster_name_test(Config) ->
@ -956,23 +963,26 @@ bindings_post_test(Config) ->
http_put(Config, "/queues/%2f/myqueue", QArgs, {group, '2xx'}),
http_post(Config, "/bindings/%2f/e/myexchange/q/badqueue", BArgs, ?NOT_FOUND),
http_post(Config, "/bindings/%2f/e/badexchange/q/myqueue", BArgs, ?NOT_FOUND),
Headers1 = http_post(Config, "/bindings/%2f/e/myexchange/q/myqueue", #{}, {group, '2xx'}),
"../../../../%2F/e/myexchange/q/myqueue/~" = pget("location", Headers1),
Want0 = "../../../../%2F/e/myexchange/q/myqueue/~",
?assertEqual(Want0, pget("location", Headers1)),
Headers2 = http_post(Config, "/bindings/%2f/e/myexchange/q/myqueue", BArgs, {group, '2xx'}),
%% Args hash is calculated from a table, generated from args.
Hash = table_hash([{<<"foo">>,longstr,<<"bar">>}]),
PropertiesKey = "routing~" ++ Hash,
Want1 = "../../../../%2F/e/myexchange/q/myqueue/" ++ PropertiesKey,
?assertEqual(Want1, pget("location", Headers2)),
PropertiesKeyBin = list_to_binary(PropertiesKey),
"../../../../%2F/e/myexchange/q/myqueue/" ++ PropertiesKey =
pget("location", Headers2),
Want2 = #{arguments => #{foo => <<"bar">>}, destination => <<"myqueue">>,
destination_type => <<"queue">>, properties_key => PropertiesKeyBin,
routing_key => <<"routing">>, source => <<"myexchange">>,vhost => <<"/">>},
URI = "/bindings/%2F/e/myexchange/q/myqueue/" ++ PropertiesKey,
#{source := <<"myexchange">>,
vhost := <<"/">>,
destination := <<"myqueue">>,
destination_type := <<"queue">>,
routing_key := <<"routing">>,
arguments := #{foo := <<"bar">>},
properties_key := PropertiesKeyBin} = http_get(Config, URI, ?OK),
?assertEqual(Want2, http_get(Config, URI, ?OK)),
http_get(Config, URI ++ "x", ?NOT_FOUND),
http_delete(Config, URI, {group, '2xx'}),
http_delete(Config, "/exchanges/%2f/myexchange", {group, '2xx'}),

View File

@ -31,7 +31,8 @@ groups() ->
{parallel_tests, [parallel], [
tokenise_test,
pack_binding_test,
amqp_table_test
amqp_table_test,
path_prefix_test
]}
].
@ -81,6 +82,25 @@ assert_table(JSON, AMQP) ->
?assertEqual(JSON, rabbit_mgmt_format:amqp_table(AMQP)),
?assertEqual(AMQP, rabbit_mgmt_format:to_amqp_table(JSON)).
path_prefix_test(_Config) ->
Got0 = rabbit_mgmt_util:get_path_prefix(),
?assertEqual("", Got0),
Pfx0 = "/custom-prefix",
application:set_env(rabbitmq_management, path_prefix, Pfx0),
Got1 = rabbit_mgmt_util:get_path_prefix(),
?assertEqual(Pfx0, Got1),
Pfx1 = "custom-prefix",
application:set_env(rabbitmq_management, path_prefix, Pfx1),
Got2 = rabbit_mgmt_util:get_path_prefix(),
?assertEqual(Pfx0, Got2),
Pfx2 = <<"custom-prefix">>,
application:set_env(rabbitmq_management, path_prefix, Pfx2),
Got3 = rabbit_mgmt_util:get_path_prefix(),
?assertEqual(Pfx0, Got3).
%%--------------------------------------------------------------------
assert_binding(Packed, Routing, Args) ->