diff --git a/deps/rabbitmq_management/priv/www/cli/index.html b/deps/rabbitmq_management/priv/www/cli/index.html index 0985b4c89f..89cd527db8 100644 --- a/deps/rabbitmq_management/priv/www/cli/index.html +++ b/deps/rabbitmq_management/priv/www/cli/index.html @@ -18,7 +18,7 @@

- To use it, download it from this node (right click, + To use it, download it from this node (right click, Save As), make sure it is executable, and drop it in your PATH. Note that many browsers will rename the file rabbitmqadmin.txt. rabbitmqadmin requires Python diff --git a/deps/rabbitmq_management/priv/www/js/global.js b/deps/rabbitmq_management/priv/www/js/global.js index ecf133924d..ce3b25bc2d 100644 --- a/deps/rabbitmq_management/priv/www/js/global.js +++ b/deps/rabbitmq_management/priv/www/js/global.js @@ -391,6 +391,10 @@ var HELP = { 'memory-use' : '

Note that the memory details shown here are only updated on request - they could be too expensive to calculate every few seconds on a busy server.

Read more on memory use.

', + 'memory-calculation-strategy-breakdown' : '

The setting vm_memory_calculation_strategy defines which of the below memory values is used to check if the memory usage reaches the watermark or paging to disk is required.

Read more on memory use.

', + + 'memory-calculation-strategy' : '

This value can be calculated using different strategies the vm_memory_calculation_strategy config setting.

Read more on memory use.

', + 'binary-use' : '

Binary accounting is not exact; binaries are shared between processes (and thus the same binary might be counted in more than one section), and the VM does not allow us to track binaries that are not associated with processes (so some binary use might not appear at all).

', 'policy-ha-mode' : 'One of all (mirror to all nodes in the cluster), exactly (mirror to a set number of nodes) or nodes (mirror to an explicit list of nodes). If you choose one of the latter two, you must also set ha-params.', diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs index 6a88d5b877..270f356536 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs @@ -65,8 +65,22 @@ var key = [[{name: 'Queues', colour: 'queue',
Last updated: <%= fmt_date(new Date()) %>.
- Total memory used at last update: <%= fmt_bytes(memory.total) %> - + Memory calculation strategy: <%= memory.strategy %>.

+ Amount of memory used vs. allocated during last update:
+ + + + + + + + + + + + + +
Runtime Used<%= fmt_bytes(memory.total.erlang) %>
Runtime Allocated<%= fmt_bytes(memory.total.allocated) %>
Resident Set Size (RSS) reported by the OS<%= fmt_bytes(memory.total.rss) %>
<% } %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs index 94b5a45dfc..6e4e42cc80 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs @@ -104,7 +104,7 @@ - Memory + Memory <% if (node.mem_limit != 'memory_monitoring_disabled') { %> diff --git a/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs index 661aed40f6..05df78c498 100644 --- a/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs @@ -82,7 +82,7 @@ Erlang processes <% } %> <% if (show_column('overview', 'memory')) { %> - Memory + Memory <% } %> <% if (show_column('overview', 'disk_space')) { %> Disk space @@ -182,6 +182,7 @@ RAM <% } %> <%= fmt_plugins_small(node) %> + <%= fmt_string(node.mem_calculation_strategy) %> <% } %> <% if(user_administrator && show_column('overview', 'reset_stats')) { %> diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl b/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl index fee85b19e0..943b16d896 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl @@ -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} <- diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_util.erl b/deps/rabbitmq_management/src/rabbit_mgmt_util.erl index 8b8babd288..a721580656 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_util.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_util.erl @@ -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 diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl index 76e573d4be..5aa5bcfc05 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl @@ -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. diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl index 113015ca59..7bdff04fde 100644 --- a/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl @@ -70,7 +70,9 @@ augment(Mode, ReqData) -> format(absolute, Result) -> Result; format(relative, Result) -> - {value, {total, Total}, Rest} = lists:keytake(total, 1, Result), + {value, {strategy, Strategy}, Rest0} = lists:keytake(strategy, 1, Result), + {value, {total, Totals}, Rest} = lists:keytake(total, 1, Rest0), + Total = proplists:get_value(Strategy, Totals), [{total, 100} | [{K, percentage(V, Total)} || {K, V} <- Rest]]. percentage(Part, Total) -> diff --git a/deps/rabbitmq_management/test/rabbit_mgmt_http_SUITE.erl b/deps/rabbitmq_management/test/rabbit_mgmt_http_SUITE.erl index 3a2bd92381..192b25a362 100644 --- a/deps/rabbitmq_management/test/rabbit_mgmt_http_SUITE.erl +++ b/deps/rabbitmq_management/test/rabbit_mgmt_http_SUITE.erl @@ -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,30 @@ 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 = #{source => <<"myexchange">>, + vhost => <<"/">>, + destination => <<"myqueue">>, + destination_type => <<"queue">>, + routing_key => <<"routing">>, + arguments => #{foo => <<"bar">>}, + properties_key => PropertiesKeyBin}, 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'}), diff --git a/deps/rabbitmq_management/test/rabbit_mgmt_test_unit_SUITE.erl b/deps/rabbitmq_management/test/rabbit_mgmt_test_unit_SUITE.erl index 2152f4b7c1..e5660c5208 100644 --- a/deps/rabbitmq_management/test/rabbit_mgmt_test_unit_SUITE.erl +++ b/deps/rabbitmq_management/test/rabbit_mgmt_test_unit_SUITE.erl @@ -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) ->