diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | docs/rabbitmqctl.1.xml | 134 | ||||
-rw-r--r-- | ebin/rabbit_app.in | 5 | ||||
-rw-r--r-- | include/rabbit.hrl | 5 | ||||
-rw-r--r-- | include/rabbit_auth_backend_spec.hrl | 3 | ||||
-rw-r--r-- | packaging/RPMS/Fedora/rabbitmq-server.spec | 3 | ||||
-rw-r--r-- | packaging/debs/Debian/debian/changelog | 6 | ||||
-rw-r--r-- | src/rabbit.erl | 29 | ||||
-rw-r--r-- | src/rabbit_access_control.erl | 27 | ||||
-rw-r--r-- | src/rabbit_amqqueue.erl | 13 | ||||
-rw-r--r-- | src/rabbit_amqqueue_process.erl | 4 | ||||
-rw-r--r-- | src/rabbit_auth_backend.erl | 8 | ||||
-rw-r--r-- | src/rabbit_auth_backend_internal.erl | 111 | ||||
-rw-r--r-- | src/rabbit_binding.erl | 35 | ||||
-rw-r--r-- | src/rabbit_control.erl | 113 | ||||
-rw-r--r-- | src/rabbit_event.erl | 12 | ||||
-rw-r--r-- | src/rabbit_exchange.erl | 21 | ||||
-rw-r--r-- | src/rabbit_router.erl | 35 | ||||
-rw-r--r-- | src/rabbit_tests.erl | 20 | ||||
-rw-r--r-- | src/rabbit_types.erl | 4 | ||||
-rw-r--r-- | src/rabbit_upgrade_functions.erl | 12 | ||||
-rw-r--r-- | src/rabbit_vhost.erl | 6 |
22 files changed, 379 insertions, 230 deletions
@@ -162,7 +162,8 @@ run-node: all ./scripts/rabbitmq-server run-tests: all - echo "rabbit_tests:all_tests()." | $(ERL_CALL) + OUT=$$(echo "rabbit_tests:all_tests()." | $(ERL_CALL)) ; \ + echo $$OUT ; echo $$OUT | grep '^{ok, passed}$$' > /dev/null start-background-node: $(BASIC_SCRIPT_ENVIRONMENT_SETTINGS) \ diff --git a/docs/rabbitmqctl.1.xml b/docs/rabbitmqctl.1.xml index b825a1d0..cc3d4d2a 100644 --- a/docs/rabbitmqctl.1.xml +++ b/docs/rabbitmqctl.1.xml @@ -59,6 +59,11 @@ RabbitMQ broker. It performs all actions by connecting to one of the broker's nodes. </para> + <para> + Diagnostic information is displayed if the broker was not + running, could not be reached, or rejected the connection due to + mismatching Erlang cookies. + </para> </refsect1> <refsect1> @@ -179,24 +184,6 @@ </listitem> </varlistentry> - <varlistentry> - <term><cmdsynopsis><command>status</command></cmdsynopsis></term> - <listitem> - <para> - Displays various information about the RabbitMQ broker, - such as whether the RabbitMQ application on the current - node, its version number, what nodes are part of the - broker, which of these are running. - </para> - <para role="example-prefix">For example:</para> - <screen role="example">rabbitmqctl status</screen> - <para role="example"> - This command displays information about the RabbitMQ - broker. - </para> - </listitem> - </varlistentry> - <varlistentry id="reset"> <term><cmdsynopsis><command>reset</command></cmdsynopsis></term> <listitem> @@ -377,6 +364,20 @@ </para> </listitem> </varlistentry> + <varlistentry> + <term><cmdsynopsis><command>cluster_status</command></cmdsynopsis></term> + <listitem> + <para> + Displays all the nodes in the cluster grouped by node type, + together with the currently running nodes. + </para> + <para role="example-prefix">For example:</para> + <screen role="example">rabbitmqctl cluster_status</screen> + <para role="example"> + This command displays the nodes in the cluster. + </para> + </listitem> + </varlistentry> </variablelist> </refsect2> @@ -512,17 +513,22 @@ </varlistentry> <varlistentry> - <term><cmdsynopsis><command>set_admin</command> <arg choice="req"><replaceable>username</replaceable></arg></cmdsynopsis></term> + <term><cmdsynopsis><command>set_user_tags</command> <arg choice="req"><replaceable>username</replaceable></arg> <arg choice="req"><replaceable>tag</replaceable> ...</arg></cmdsynopsis></term> <listitem> <variablelist> <varlistentry> <term>username</term> - <listitem><para>The name of the user whose administrative - status is to be set.</para></listitem> + <listitem><para>The name of the user whose tags are to + be set.</para></listitem> + </varlistentry> + <varlistentry> + <term>tag</term> + <listitem><para>Zero, one or more tags to set. Any + existing tags will be removed.</para></listitem> </varlistentry> </variablelist> <para role="example-prefix">For example:</para> - <screen role="example">rabbitmqctl set_admin tonyg</screen> + <screen role="example">rabbitmqctl set_user_tags tonyg administrator</screen> <para role="example"> This command instructs the RabbitMQ broker to ensure the user named <command>tonyg</command> is an administrator. This has no @@ -531,24 +537,10 @@ user logs in via some other means (for example with the management plugin). </para> - </listitem> - </varlistentry> - - <varlistentry> - <term><cmdsynopsis><command>clear_admin</command> <arg choice="req"><replaceable>username</replaceable></arg></cmdsynopsis></term> - <listitem> - <variablelist> - <varlistentry> - <term>username</term> - <listitem><para>The name of the user whose administrative - status is to be cleared.</para></listitem> - </varlistentry> - </variablelist> - <para role="example-prefix">For example:</para> - <screen role="example">rabbitmqctl clear_admin tonyg</screen> + <screen role="example">rabbitmqctl set_user_tags tonyg</screen> <para role="example"> - This command instructs the RabbitMQ broker to ensure the user - named <command>tonyg</command> is not an administrator. + This command instructs the RabbitMQ broker to remove any + tags from the user named <command>tonyg</command>. </para> </listitem> </varlistentry> @@ -647,6 +639,10 @@ <listitem><para>Whether tracing is enabled for this virtual host.</para></listitem> </varlistentry> </variablelist> + <para> + If no <command>vhostinfoitem</command>s are specified + then the vhost name is displayed. + </para> <para role="example-prefix">For example:</para> <screen role="example">rabbitmqctl list_vhosts name tracing</screen> <para role="example"> @@ -1259,7 +1255,7 @@ </varlistentry> <varlistentry> - <term><cmdsynopsis><command>list_consumers</command></cmdsynopsis></term> + <term><cmdsynopsis><command>list_consumers</command> <arg choice="opt">-p <replaceable>vhostpath</replaceable></arg></cmdsynopsis></term> <listitem> <para> List consumers, i.e. subscriptions to a queue's message @@ -1271,11 +1267,59 @@ indicating whether acknowledgements are expected for messages delivered to this consumer. </para> - <para role="usage"> - The output format for "list_consumers" is a list of rows containing, - in order, the queue name, channel process id, consumer tag, and a - boolean indicating whether acknowledgements are expected from the - consumer. + <para> + The output is a list of rows containing, in order, the queue name, + channel process id, consumer tag, and a boolean indicating whether + acknowledgements are expected from the consumer. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><cmdsynopsis><command>status</command></cmdsynopsis></term> + <listitem> + <para> + Displays broker status information such as the running + applications on the current Erlang node, RabbitMQ and + Erlang versions and OS name. (See + the <command>cluster_status</command> command to find + out which nodes are clustered and running.) + </para> + <para role="example-prefix">For example:</para> + <screen role="example">rabbitmqctl status</screen> + <para role="example"> + This command displays information about the RabbitMQ + broker. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><cmdsynopsis><command>environment</command></cmdsynopsis></term> + <listitem> + <para> + Display the name and value of each variable in the + application environment. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><cmdsynopsis><command>report</command></cmdsynopsis></term> + <listitem> + <para> + Generate a server status report containing a + concatenation of all server status information for + support purposes. The output should be redirected to a + file when accompanying a support request. + </para> + <para role="example-prefix"> + For example: + </para> + <screen role="example">rabbitmqctl report > server_report.txt</screen> + <para role="example"> + This command creates a server report which may be + attached to a support request email. </para> </listitem> </varlistentry> diff --git a/ebin/rabbit_app.in b/ebin/rabbit_app.in index 7dabb8c3..65a3269a 100644 --- a/ebin/rabbit_app.in +++ b/ebin/rabbit_app.in @@ -21,18 +21,17 @@ {msg_store_index_module, rabbit_msg_store_ets_index}, {backing_queue_module, rabbit_variable_queue}, {frame_max, 131072}, - {persister_max_wrap_entries, 500}, - {persister_hibernate_after, 10000}, {msg_store_file_size_limit, 16777216}, {queue_index_max_journal_entries, 262144}, {default_user, <<"guest">>}, {default_pass, <<"guest">>}, - {default_user_is_admin, true}, + {default_user_tags, [administrator]}, {default_vhost, <<"/">>}, {default_permissions, [<<".*">>, <<".*">>, <<".*">>]}, {cluster_nodes, []}, {server_properties, []}, {collect_statistics, none}, + {collect_statistics_interval, 5000}, {auth_mechanisms, ['PLAIN', 'AMQPLAIN']}, {auth_backends, [rabbit_auth_backend_internal]}, {delegate_count, 16}, diff --git a/include/rabbit.hrl b/include/rabbit.hrl index 1388f3c4..0a202c5e 100644 --- a/include/rabbit.hrl +++ b/include/rabbit.hrl @@ -15,12 +15,12 @@ %% -record(user, {username, - is_admin, + tags, auth_backend, %% Module this user came from impl %% Scratch space for that module }). --record(internal_user, {username, password_hash, is_admin}). +-record(internal_user, {username, password_hash, tags}). -record(permission, {configure, write, read}). -record(user_vhost, {username, virtual_host}). -record(user_permission, {user_vhost, permission}). @@ -86,7 +86,6 @@ -define(HIBERNATE_AFTER_MIN, 1000). -define(DESIRED_HIBERNATE, 10000). --define(STATS_INTERVAL, 5000). -define(ROUTING_HEADERS, [<<"CC">>, <<"BCC">>]). -define(DELETED_HEADER, <<"BCC">>). diff --git a/include/rabbit_auth_backend_spec.hrl b/include/rabbit_auth_backend_spec.hrl index e26d44ea..803bb75c 100644 --- a/include/rabbit_auth_backend_spec.hrl +++ b/include/rabbit_auth_backend_spec.hrl @@ -22,8 +22,7 @@ {'ok', rabbit_types:user()} | {'refused', string(), [any()]} | {'error', any()}). --spec(check_vhost_access/3 :: (rabbit_types:user(), rabbit_types:vhost(), - rabbit_access_control:vhost_permission_atom()) -> +-spec(check_vhost_access/2 :: (rabbit_types:user(), rabbit_types:vhost()) -> boolean() | {'error', any()}). -spec(check_resource_access/3 :: (rabbit_types:user(), rabbit_types:r(atom()), diff --git a/packaging/RPMS/Fedora/rabbitmq-server.spec b/packaging/RPMS/Fedora/rabbitmq-server.spec index f9e9df8b..ffc826eb 100644 --- a/packaging/RPMS/Fedora/rabbitmq-server.spec +++ b/packaging/RPMS/Fedora/rabbitmq-server.spec @@ -120,6 +120,9 @@ done rm -rf %{buildroot} %changelog +* Thu Jun 9 2011 jerryk@vmware.com 2.5.0-1 +- New Upstream Release + * Thu Apr 7 2011 Alexandru Scvortov <alexandru@rabbitmq.com> 2.4.1-1 - New Upstream Release diff --git a/packaging/debs/Debian/debian/changelog b/packaging/debs/Debian/debian/changelog index 0383b955..1cab4235 100644 --- a/packaging/debs/Debian/debian/changelog +++ b/packaging/debs/Debian/debian/changelog @@ -1,3 +1,9 @@ +rabbitmq-server (2.5.0-1) lucid; urgency=low + + * New Upstream Release + + -- <jerryk@vmware.com> Thu, 09 Jun 2011 07:20:29 -0700 + rabbitmq-server (2.4.1-1) lucid; urgency=low * New Upstream Release diff --git a/src/rabbit.erl b/src/rabbit.erl index e6e80b4a..100cacb0 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -18,7 +18,7 @@ -behaviour(application). --export([prepare/0, start/0, stop/0, stop_and_halt/0, status/0, +-export([prepare/0, start/0, stop/0, stop_and_halt/0, status/0, environment/0, rotate_logs/1]). -export([start/2, stop/1]). @@ -178,9 +178,12 @@ -spec(stop_and_halt/0 :: () -> 'ok'). -spec(rotate_logs/1 :: (file_suffix()) -> rabbit_types:ok_or_error(any())). -spec(status/0 :: - () -> [{running_applications, [{atom(), string(), string()}]} | - {nodes, [{rabbit_mnesia:node_type(), [node()]}]} | - {running_nodes, [node()]}]). + () -> [{pid, integer()} | + {running_applications, [{atom(), string(), string()}]} | + {os, {atom(), atom()}} | + {erlang_version, string()} | + {memory, any()}]). +-spec(environment/0 :: () -> [{atom() | term()}]). -spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()). -spec(maybe_insert_default_data/0 :: () -> 'ok'). @@ -217,8 +220,15 @@ stop_and_halt() -> status() -> [{pid, list_to_integer(os:getpid())}, - {running_applications, application:which_applications()}] ++ - rabbit_mnesia:status(). + {running_applications, application:which_applications()}, + {os, os:type()}, + {erlang_version, erlang:system_info(system_version)}, + {memory, erlang:memory()}]. + +environment() -> + lists:keysort( + 1, [P || P = {K, _} <- application:get_all_env(rabbit), + K =/= default_pass]). rotate_logs(BinarySuffix) -> Suffix = binary_to_list(BinarySuffix), @@ -476,16 +486,13 @@ maybe_insert_default_data() -> insert_default_data() -> {ok, DefaultUser} = application:get_env(default_user), {ok, DefaultPass} = application:get_env(default_pass), - {ok, DefaultAdmin} = application:get_env(default_user_is_admin), + {ok, DefaultTags} = application:get_env(default_user_tags), {ok, DefaultVHost} = application:get_env(default_vhost), {ok, [DefaultConfigurePerm, DefaultWritePerm, DefaultReadPerm]} = application:get_env(default_permissions), ok = rabbit_vhost:add(DefaultVHost), ok = rabbit_auth_backend_internal:add_user(DefaultUser, DefaultPass), - case DefaultAdmin of - true -> rabbit_auth_backend_internal:set_admin(DefaultUser); - _ -> ok - end, + ok = rabbit_auth_backend_internal:set_tags(DefaultUser, DefaultTags), ok = rabbit_auth_backend_internal:set_permissions(DefaultUser, DefaultVHost, DefaultConfigurePerm, DefaultWritePerm, diff --git a/src/rabbit_access_control.erl b/src/rabbit_access_control.erl index 59c00848..c0ae18c0 100644 --- a/src/rabbit_access_control.erl +++ b/src/rabbit_access_control.erl @@ -19,16 +19,15 @@ -include("rabbit.hrl"). -export([check_user_pass_login/2, check_user_login/2, - check_vhost_access/2, check_resource_access/3, list_vhosts/2]). + check_vhost_access/2, check_resource_access/3]). %%---------------------------------------------------------------------------- -ifdef(use_specs). --export_type([permission_atom/0, vhost_permission_atom/0]). +-export_type([permission_atom/0]). -type(permission_atom() :: 'configure' | 'read' | 'write'). --type(vhost_permission_atom() :: 'read' | 'write'). -spec(check_user_pass_login/2 :: (rabbit_types:username(), rabbit_types:password()) @@ -39,8 +38,6 @@ -spec(check_resource_access/3 :: (rabbit_types:user(), rabbit_types:r(atom()), permission_atom()) -> 'ok' | rabbit_types:channel_exit()). --spec(list_vhosts/2 :: (rabbit_types:user(), vhost_permission_atom()) - -> [rabbit_types:vhost()]). -endif. @@ -70,7 +67,7 @@ check_vhost_access(User = #user{ username = Username, check_access( fun() -> rabbit_vhost:exists(VHostPath) andalso - Module:check_vhost_access(User, VHostPath, write) + Module:check_vhost_access(User, VHostPath) end, "~s failed checking vhost access to ~s for ~s: ~p~n", [Module, VHostPath, Username], @@ -104,21 +101,3 @@ check_access(Fun, ErrStr, ErrArgs, RefStr, RefArgs) -> false -> rabbit_misc:protocol_error(access_refused, RefStr, RefArgs) end. - -%% Permission = write -> log in -%% Permission = read -> learn of the existence of (only relevant for -%% management plugin) -list_vhosts(User = #user{username = Username, auth_backend = Module}, - Permission) -> - lists:filter( - fun(VHost) -> - case Module:check_vhost_access(User, VHost, Permission) of - {error, _} = E -> - rabbit_log:warning("~w failed checking vhost access " - "to ~s for ~s: ~p~n", - [Module, VHost, Username, E]), - false; - Else -> - Else - end - end, rabbit_vhost:list()). diff --git a/src/rabbit_amqqueue.erl b/src/rabbit_amqqueue.erl index 7f46b870..e5c53620 100644 --- a/src/rabbit_amqqueue.erl +++ b/src/rabbit_amqqueue.erl @@ -22,7 +22,7 @@ check_exclusive_access/2, with_exclusive_access_or_die/3, stat/1, deliver/2, requeue/3, ack/4, reject/4]). -export([list/1, info_keys/0, info/1, info/2, info_all/1, info_all/2]). --export([consumers/1, consumers_all/1]). +-export([consumers/1, consumers_all/1, consumer_info_keys/0]). -export([basic_get/3, basic_consume/7, basic_cancel/4]). -export([notify_sent/2, unblock/2, flush_all/2]). -export([commit_all/3, rollback_all/3, notify_down_all/2, limit_all/3]). @@ -94,6 +94,7 @@ -spec(consumers/1 :: (rabbit_types:amqqueue()) -> [{pid(), rabbit_types:ctag(), boolean()}]). +-spec(consumer_info_keys/0 :: () -> rabbit_types:info_keys()). -spec(consumers_all/1 :: (rabbit_types:vhost()) -> [{name(), pid(), rabbit_types:ctag(), boolean()}]). @@ -161,6 +162,9 @@ %%---------------------------------------------------------------------------- +-define(CONSUMER_INFO_KEYS, + [queue_name, channel_pid, consumer_tag, ack_required]). + start() -> DurableQueues = find_durable_queues(), {ok, BQ} = application:get_env(rabbit, backing_queue_module), @@ -363,10 +367,15 @@ info_all(VHostPath, Items) -> map(VHostPath, fun (Q) -> info(Q, Items) end). consumers(#amqqueue{ pid = QPid }) -> delegate_call(QPid, consumers). +consumer_info_keys() -> ?CONSUMER_INFO_KEYS. + consumers_all(VHostPath) -> + ConsumerInfoKeys=consumer_info_keys(), lists:append( map(VHostPath, - fun (Q) -> [{Q#amqqueue.name, ChPid, ConsumerTag, AckRequired} || + fun (Q) -> + [lists:zip(ConsumerInfoKeys, + [Q#amqqueue.name, ChPid, ConsumerTag, AckRequired]) || {ChPid, ConsumerTag, AckRequired} <- consumers(Q)] end)). diff --git a/src/rabbit_amqqueue_process.erl b/src/rabbit_amqqueue_process.erl index 17c35e90..e7cb67a2 100644 --- a/src/rabbit_amqqueue_process.erl +++ b/src/rabbit_amqqueue_process.erl @@ -465,9 +465,7 @@ confirm_messages(MsgIds, State = #q{msg_id_to_channel = MTC}) -> {CMs, MTC0} end end, {gb_trees:empty(), MTC}, MsgIds), - gb_trees_foreach(fun(ChPid, MsgSeqNos) -> - rabbit_channel:confirm(ChPid, MsgSeqNos) - end, CMs), + gb_trees_foreach(fun rabbit_channel:confirm/2, CMs), State#q{msg_id_to_channel = MTC1}. gb_trees_foreach(_, none) -> diff --git a/src/rabbit_auth_backend.erl b/src/rabbit_auth_backend.erl index 09820c5b..ade158bb 100644 --- a/src/rabbit_auth_backend.erl +++ b/src/rabbit_auth_backend.erl @@ -36,17 +36,13 @@ behaviour_info(callbacks) -> %% Client failed authentication. Log and die. {check_user_login, 2}, - %% Given #user, vhost path and permission, can a user access a vhost? - %% Permission is read - learn of the existence of (only relevant for - %% management plugin) - %% or write - log in - %% + %% Given #user and vhost, can a user log in to a vhost? %% Possible responses: %% true %% false %% {error, Error} %% Something went wrong. Log and die. - {check_vhost_access, 3}, + {check_vhost_access, 2}, %% Given #user, resource and permission, can a user access a resource? %% diff --git a/src/rabbit_auth_backend_internal.erl b/src/rabbit_auth_backend_internal.erl index f70813d1..6a018bd1 100644 --- a/src/rabbit_auth_backend_internal.erl +++ b/src/rabbit_auth_backend_internal.erl @@ -20,15 +20,17 @@ -behaviour(rabbit_auth_backend). -export([description/0]). --export([check_user_login/2, check_vhost_access/3, check_resource_access/3]). +-export([check_user_login/2, check_vhost_access/2, check_resource_access/3]). --export([add_user/2, delete_user/1, change_password/2, set_admin/1, - clear_admin/1, list_users/0, lookup_user/1, clear_password/1]). +-export([add_user/2, delete_user/1, change_password/2, set_tags/2, + list_users/0, user_info_keys/0, lookup_user/1, clear_password/1]). -export([make_salt/0, check_password/2, change_password_hash/2, hash_password/1]). -export([set_permissions/5, clear_permissions/2, list_permissions/0, list_vhost_permissions/1, list_user_permissions/1, - list_user_vhost_permissions/2]). + list_user_vhost_permissions/2, perms_info_keys/0, + vhost_perms_info_keys/0, user_perms_info_keys/0, + user_vhost_perms_info_keys/0]). -include("rabbit_auth_backend_spec.hrl"). @@ -48,9 +50,9 @@ rabbit_types:password_hash()) -> 'ok'). -spec(hash_password/1 :: (rabbit_types:password()) -> rabbit_types:password_hash()). --spec(set_admin/1 :: (rabbit_types:username()) -> 'ok'). --spec(clear_admin/1 :: (rabbit_types:username()) -> 'ok'). --spec(list_users/0 :: () -> [{rabbit_types:username(), boolean()}]). +-spec(set_tags/2 :: (rabbit_types:username(), [atom()]) -> 'ok'). +-spec(list_users/0 :: () -> rabbit_types:infos()). +-spec(user_info_keys/0 :: () -> rabbit_types:info_keys()). -spec(lookup_user/1 :: (rabbit_types:username()) -> rabbit_types:ok(rabbit_types:internal_user()) | rabbit_types:error('not_found')). @@ -58,23 +60,25 @@ regexp(), regexp(), regexp()) -> 'ok'). -spec(clear_permissions/2 :: (rabbit_types:username(), rabbit_types:vhost()) -> 'ok'). --spec(list_permissions/0 :: - () -> [{rabbit_types:username(), rabbit_types:vhost(), - regexp(), regexp(), regexp()}]). +-spec(list_permissions/0 :: () -> rabbit_types:infos()). -spec(list_vhost_permissions/1 :: - (rabbit_types:vhost()) -> [{rabbit_types:username(), - regexp(), regexp(), regexp()}]). + (rabbit_types:vhost()) -> rabbit_types:infos()). -spec(list_user_permissions/1 :: - (rabbit_types:username()) -> [{rabbit_types:vhost(), - regexp(), regexp(), regexp()}]). + (rabbit_types:username()) -> rabbit_types:infos()). -spec(list_user_vhost_permissions/2 :: (rabbit_types:username(), rabbit_types:vhost()) - -> [{regexp(), regexp(), regexp()}]). - + -> rabbit_types:infos()). +-spec(perms_info_keys/0 :: () -> rabbit_types:info_keys()). +-spec(vhost_perms_info_keys/0 :: () -> rabbit_types:info_keys()). +-spec(user_perms_info_keys/0 :: () -> rabbit_types:info_keys()). +-spec(user_vhost_perms_info_keys/0 :: () -> rabbit_types:info_keys()). -endif. %%---------------------------------------------------------------------------- +-define(PERMS_INFO_KEYS, [configure, write, read]). +-define(USER_INFO_KEYS, [user, tags]). + %% Implementation of rabbit_auth_backend description() -> @@ -94,10 +98,10 @@ check_user_login(Username, AuthProps) -> internal_check_user_login(Username, Fun) -> Refused = {refused, "user '~s' - invalid credentials", [Username]}, case lookup_user(Username) of - {ok, User = #internal_user{is_admin = IsAdmin}} -> + {ok, User = #internal_user{tags = Tags}} -> case Fun(User) of true -> {ok, #user{username = Username, - is_admin = IsAdmin, + tags = Tags, auth_backend = ?MODULE, impl = User}}; _ -> Refused @@ -106,16 +110,13 @@ internal_check_user_login(Username, Fun) -> Refused end. -check_vhost_access(#user{is_admin = true}, _VHostPath, read) -> - true; - -check_vhost_access(#user{username = Username}, VHostPath, _) -> +check_vhost_access(#user{username = Username}, VHost) -> %% TODO: use dirty ops instead rabbit_misc:execute_mnesia_transaction( fun () -> case mnesia:read({rabbit_user_permission, #user_vhost{username = Username, - virtual_host = VHostPath}}) of + virtual_host = VHost}}) of [] -> false; [_R] -> true end @@ -158,7 +159,7 @@ add_user(Username, Password) -> #internal_user{username = Username, password_hash = hash_password(Password), - is_admin = false}, + tags = []}, write); _ -> mnesia:abort({user_already_exists, Username}) @@ -219,16 +220,12 @@ salted_md5(Salt, Cleartext) -> Salted = <<Salt/binary, Cleartext/binary>>, erlang:md5(Salted). -set_admin(Username) -> set_admin(Username, true). - -clear_admin(Username) -> set_admin(Username, false). - -set_admin(Username, IsAdmin) -> +set_tags(Username, Tags) -> R = update_user(Username, fun(User) -> - User#internal_user{is_admin = IsAdmin} + User#internal_user{tags = Tags} end), - rabbit_log:info("Set user admin flag for user ~p to ~p~n", - [Username, IsAdmin]), + rabbit_log:info("Set user tags for user ~p to ~p~n", + [Username, Tags]), R. update_user(Username, Fun) -> @@ -241,10 +238,12 @@ update_user(Username, Fun) -> end)). list_users() -> - [{Username, IsAdmin} || - #internal_user{username = Username, is_admin = IsAdmin} <- + [[{user, Username}, {tags, Tags}] || + #internal_user{username = Username, tags = Tags} <- mnesia:dirty_match_object(rabbit_user, #internal_user{_ = '_'})]. +user_info_keys() -> ?USER_INFO_KEYS. + lookup_user(Username) -> rabbit_misc:dirty_read({rabbit_user, Username}). @@ -283,32 +282,38 @@ clear_permissions(Username, VHostPath) -> virtual_host = VHostPath}}) end)). +perms_info_keys() -> [user, vhost | ?PERMS_INFO_KEYS]. +vhost_perms_info_keys() -> [user | ?PERMS_INFO_KEYS]. +user_perms_info_keys() -> [vhost | ?PERMS_INFO_KEYS]. +user_vhost_perms_info_keys() -> ?PERMS_INFO_KEYS. + list_permissions() -> - [{Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm} || - {Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm} <- - list_permissions(match_user_vhost('_', '_'))]. + list_permissions(perms_info_keys(), match_user_vhost('_', '_')). list_vhost_permissions(VHostPath) -> - [{Username, ConfigurePerm, WritePerm, ReadPerm} || - {Username, _, ConfigurePerm, WritePerm, ReadPerm} <- - list_permissions(rabbit_vhost:with( - VHostPath, match_user_vhost('_', VHostPath)))]. + list_permissions( + vhost_perms_info_keys(), + rabbit_vhost:with(VHostPath, match_user_vhost('_', VHostPath))). list_user_permissions(Username) -> - [{VHostPath, ConfigurePerm, WritePerm, ReadPerm} || - {_, VHostPath, ConfigurePerm, WritePerm, ReadPerm} <- - list_permissions(rabbit_misc:with_user( - Username, match_user_vhost(Username, '_')))]. + list_permissions( + user_perms_info_keys(), + rabbit_misc:with_user(Username, match_user_vhost(Username, '_'))). list_user_vhost_permissions(Username, VHostPath) -> - [{ConfigurePerm, WritePerm, ReadPerm} || - {_, _, ConfigurePerm, WritePerm, ReadPerm} <- - list_permissions(rabbit_misc:with_user_and_vhost( - Username, VHostPath, - match_user_vhost(Username, VHostPath)))]. - -list_permissions(QueryThunk) -> - [{Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm} || + list_permissions( + user_vhost_perms_info_keys(), + rabbit_misc:with_user_and_vhost( + Username, VHostPath, match_user_vhost(Username, VHostPath))). + +filter_props(Keys, Props) -> [T || T = {K, _} <- Props, lists:member(K, Keys)]. + +list_permissions(Keys, QueryThunk) -> + [filter_props(Keys, [{user, Username}, + {vhost, VHostPath}, + {configure, ConfigurePerm}, + {write, WritePerm}, + {read, ReadPerm}]) || #user_permission{user_vhost = #user_vhost{username = Username, virtual_host = VHostPath}, permission = #permission{ configure = ConfigurePerm, diff --git a/src/rabbit_binding.erl b/src/rabbit_binding.erl index 2f71bfab..5873537c 100644 --- a/src/rabbit_binding.erl +++ b/src/rabbit_binding.erl @@ -198,22 +198,33 @@ list(VHostPath) -> Route)]. list_for_source(SrcName) -> - Route = #route{binding = #binding{source = SrcName, _ = '_'}}, - [B || #route{binding = B} <- mnesia:dirty_match_object(rabbit_route, - Route)]. + mnesia:async_dirty( + fun() -> + Route = #route{binding = #binding{source = SrcName, _ = '_'}}, + [B || #route{binding = B} + <- mnesia:match_object(rabbit_route, Route, read)] + end). list_for_destination(DstName) -> - Route = #route{binding = #binding{destination = DstName, _ = '_'}}, - [reverse_binding(B) || #reverse_route{reverse_binding = B} <- - mnesia:dirty_match_object(rabbit_reverse_route, - reverse_route(Route))]. + mnesia:async_dirty( + fun() -> + Route = #route{binding = #binding{destination = DstName, + _ = '_'}}, + [reverse_binding(B) || + #reverse_route{reverse_binding = B} <- + mnesia:match_object(rabbit_reverse_route, + reverse_route(Route), read)] + end). list_for_source_and_destination(SrcName, DstName) -> - Route = #route{binding = #binding{source = SrcName, - destination = DstName, - _ = '_'}}, - [B || #route{binding = B} <- mnesia:dirty_match_object(rabbit_route, - Route)]. + mnesia:async_dirty( + fun() -> + Route = #route{binding = #binding{source = SrcName, + destination = DstName, + _ = '_'}}, + [B || #route{binding = B} <- mnesia:match_object(rabbit_route, + Route, read)] + end). info_keys() -> ?INFO_KEYS. diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl index 117496f5..9194a45b 100644 --- a/src/rabbit_control.erl +++ b/src/rabbit_control.erl @@ -26,6 +26,19 @@ -define(NODE_OPT, "-n"). -define(VHOST_OPT, "-p"). +-define(GLOBAL_QUERIES, + [{"Connections", rabbit_networking, connection_info_all, + connection_info_keys}, + {"Channels", rabbit_channel, info_all, info_keys}]). + +-define(VHOST_QUERIES, + [{"Queues", rabbit_amqqueue, info_all, info_keys}, + {"Exchanges", rabbit_exchange, info_all, info_keys}, + {"Bindings", rabbit_binding, info_all, info_keys}, + {"Consumers", rabbit_amqqueue, consumers_all, consumer_info_keys}, + {"Permissions", rabbit_auth_backend_internal, list_vhost_permissions, + vhost_perms_info_keys}]). + %%---------------------------------------------------------------------------- -ifdef(use_specs). @@ -96,6 +109,23 @@ start() -> fmt_stderr(Format, Args) -> rabbit_misc:format_stderr(Format ++ "~n", Args). +print_report(Node, {Descr, Module, InfoFun, KeysFun}) -> + io:format("~s:~n", [Descr]), + print_report0(Node, {Module, InfoFun, KeysFun}, []). + +print_report(Node, {Descr, Module, InfoFun, KeysFun}, VHostArg) -> + io:format("~s on ~s:~n", [Descr, VHostArg]), + print_report0(Node, {Module, InfoFun, KeysFun}, VHostArg). + +print_report0(Node, {Module, InfoFun, KeysFun}, VHostArg) -> + case Results = rpc_call(Node, Module, InfoFun, VHostArg) of + [_|_] -> InfoItems = rpc_call(Node, Module, KeysFun, []), + display_row([atom_to_list(I) || I <- InfoItems]), + display_info_list(Results, InfoItems); + _ -> ok + end, + io:nl(). + print_error(Format, Args) -> fmt_stderr("Error: " ++ Format, Args). print_badrpc_diagnostics(Node) -> @@ -167,11 +197,15 @@ action(wait, Node, [], _Opts, Inform) -> action(status, Node, [], _Opts, Inform) -> Inform("Status of node ~p", [Node]), - case call(Node, {rabbit, status, []}) of - {badrpc, _} = Res -> Res; - Res -> io:format("~p~n", [Res]), - ok - end; + display_call_result(Node, {rabbit, status, []}); + +action(cluster_status, Node, [], _Opts, Inform) -> + Inform("Cluster status of node ~p", [Node]), + display_call_result(Node, {rabbit_mnesia, status, []}); + +action(environment, Node, _App, _Opts, Inform) -> + Inform("Application environment of node ~p", [Node]), + display_call_result(Node, {rabbit, environment, []}); action(rotate_logs, Node, [], _Opts, Inform) -> Inform("Reopening logs for node ~p", [Node]), @@ -201,17 +235,17 @@ action(clear_password, Node, Args = [Username], _Opts, Inform) -> Inform("Clearing password for user ~p", [Username]), call(Node, {rabbit_auth_backend_internal, clear_password, Args}); -action(set_admin, Node, [Username], _Opts, Inform) -> - Inform("Setting administrative status for user ~p", [Username]), - call(Node, {rabbit_auth_backend_internal, set_admin, [Username]}); - -action(clear_admin, Node, [Username], _Opts, Inform) -> - Inform("Clearing administrative status for user ~p", [Username]), - call(Node, {rabbit_auth_backend_internal, clear_admin, [Username]}); +action(set_user_tags, Node, [Username | TagsStr], _Opts, Inform) -> + Tags = [list_to_atom(T) || T <- TagsStr], + Inform("Setting tags for user ~p to ~p", [Username, Tags]), + rpc_call(Node, rabbit_auth_backend_internal, set_tags, + [list_to_binary(Username), Tags]); action(list_users, Node, [], _Opts, Inform) -> Inform("Listing users", []), - display_list(call(Node, {rabbit_auth_backend_internal, list_users, []})); + display_info_list( + call(Node, {rabbit_auth_backend_internal, list_users, []}), + rabbit_auth_backend_internal:user_info_keys()); action(add_vhost, Node, Args = [_VHostPath], _Opts, Inform) -> Inform("Creating vhost ~p", Args), @@ -228,8 +262,9 @@ action(list_vhosts, Node, Args, _Opts, Inform) -> action(list_user_permissions, Node, Args = [_Username], _Opts, Inform) -> Inform("Listing permissions for user ~p", Args), - display_list(call(Node, {rabbit_auth_backend_internal, - list_user_permissions, Args})); + display_info_list(call(Node, {rabbit_auth_backend_internal, + list_user_permissions, Args}), + rabbit_auth_backend_internal:user_perms_info_keys()); action(list_queues, Node, Args, Opts, Inform) -> Inform("Listing queues", []), @@ -286,14 +321,8 @@ action(list_channels, Node, Args, _Opts, Inform) -> action(list_consumers, Node, _Args, Opts, Inform) -> Inform("Listing consumers", []), VHostArg = list_to_binary(proplists:get_value(?VHOST_OPT, Opts)), - InfoKeys = [queue_name, channel_pid, consumer_tag, ack_required], - case rpc_call(Node, rabbit_amqqueue, consumers_all, [VHostArg]) of - L when is_list(L) -> display_info_list( - [lists:zip(InfoKeys, tuple_to_list(X)) || - X <- L], - InfoKeys); - Other -> Other - end; + display_info_list(rpc_call(Node, rabbit_amqqueue, consumers_all, [VHostArg]), + rabbit_amqqueue:consumer_info_keys()); action(trace_on, Node, [], Opts, Inform) -> VHost = proplists:get_value(?VHOST_OPT, Opts), @@ -320,8 +349,20 @@ action(clear_permissions, Node, [Username], Opts, Inform) -> action(list_permissions, Node, [], Opts, Inform) -> VHost = proplists:get_value(?VHOST_OPT, Opts), Inform("Listing permissions in vhost ~p", [VHost]), - display_list(call(Node, {rabbit_auth_backend_internal, - list_vhost_permissions, [VHost]})). + display_info_list(call(Node, {rabbit_auth_backend_internal, + list_vhost_permissions, [VHost]}), + rabbit_auth_backend_internal:vhost_perms_info_keys()); + +action(report, Node, _Args, _Opts, Inform) -> + io:format("Reporting server status on ~p~n~n", [erlang:universaltime()]), + [begin ok = action(Action, N, [], [], Inform), io:nl() end || + N <- unsafe_rpc(Node, rabbit_mnesia, running_clustered_nodes, []), + Action <- [status, cluster_status, environment]], + VHosts = unsafe_rpc(Node, rabbit_vhost, list, []), + [print_report(Node, Q) || Q <- ?GLOBAL_QUERIES], + [print_report(Node, Q, [V]) || Q <- ?VHOST_QUERIES, V <- VHosts], + io:format("End of server status report~n"), + ok. %%---------------------------------------------------------------------------- @@ -393,16 +434,18 @@ format_info_item([T | _] = Value) format_info_item(Value) -> io_lib:format("~w", [Value]). -display_list(L) when is_list(L) -> - lists:foreach(fun (I) when is_binary(I) -> - io:format("~s~n", [escape(I)]); - (I) when is_tuple(I) -> - display_row([escape(V) - || V <- tuple_to_list(I)]) - end, - lists:sort(L)), - ok; -display_list(Other) -> Other. +display_call_result(Node, MFA) -> + case call(Node, MFA) of + {badrpc, _} = Res -> throw(Res); + Res -> io:format("~p~n", [Res]), + ok + end. + +unsafe_rpc(Node, Mod, Fun, Args) -> + case rpc_call(Node, Mod, Fun, Args) of + {badrpc, _} = Res -> throw(Res); + Normal -> Normal + end. call(Node, {Mod, Fun, Args}) -> rpc_call(Node, Mod, Fun, lists:map(fun list_to_binary/1, Args)). diff --git a/src/rabbit_event.erl b/src/rabbit_event.erl index 9ed532db..468f9293 100644 --- a/src/rabbit_event.erl +++ b/src/rabbit_event.erl @@ -26,7 +26,7 @@ %%---------------------------------------------------------------------------- --record(state, {level, timer}). +-record(state, {level, interval, timer}). %%---------------------------------------------------------------------------- @@ -49,6 +49,7 @@ -opaque(state() :: #state { level :: level(), + interval :: integer(), timer :: atom() }). @@ -95,13 +96,14 @@ start_link() -> init_stats_timer() -> {ok, StatsLevel} = application:get_env(rabbit, collect_statistics), - #state{level = StatsLevel, timer = undefined}. + {ok, Interval} = application:get_env(rabbit, collect_statistics_interval), + #state{level = StatsLevel, interval = Interval, timer = undefined}. ensure_stats_timer(State = #state{level = none}, _Fun) -> State; -ensure_stats_timer(State = #state{timer = undefined}, Fun) -> - {ok, TRef} = timer:apply_after(?STATS_INTERVAL, - erlang, apply, [Fun, []]), +ensure_stats_timer(State = #state{interval = Interval, + timer = undefined}, Fun) -> + {ok, TRef} = timer:apply_after(Interval, erlang, apply, [Fun, []]), State#state{timer = TRef}; ensure_stats_timer(State, _Fun) -> State. diff --git a/src/rabbit_exchange.erl b/src/rabbit_exchange.erl index 84a44cd2..cab1b99f 100644 --- a/src/rabbit_exchange.erl +++ b/src/rabbit_exchange.erl @@ -24,7 +24,7 @@ info_keys/0, info/1, info/2, info_all/1, info_all/2, publish/2, delete/2]). %% these must be run inside a mnesia tx --export([maybe_auto_delete/1, serial/1]). +-export([maybe_auto_delete/1, serial/1, peek_serial/1]). %%---------------------------------------------------------------------------- @@ -75,7 +75,8 @@ -spec(maybe_auto_delete/1:: (rabbit_types:exchange()) -> 'not_deleted' | {'deleted', rabbit_binding:deletions()}). --spec(serial/1:: (rabbit_types:exchange()) -> 'none' | pos_integer()). +-spec(serial/1 :: (rabbit_types:exchange()) -> 'none' | pos_integer()). +-spec(peek_serial/1 :: (name()) -> pos_integer() | 'undefined'). -endif. @@ -93,7 +94,7 @@ recover() -> true -> store(X); false -> ok end, - rabbit_exchange:callback(X, create, [Tx, X]) + rabbit_exchange:callback(X, create, [map_create_tx(Tx), X]) end, rabbit_durable_exchange), [XName || #exchange{name = XName} <- Xs]. @@ -127,10 +128,7 @@ declare(XName, Type, Durable, AutoDelete, Internal, Args) -> end end, fun ({new, Exchange}, Tx) -> - ok = XT:create(case Tx of - true -> transaction; - false -> none - end, Exchange), + ok = XT:create(map_create_tx(Tx), Exchange), rabbit_event:notify_if(not Tx, exchange_created, info(Exchange)), Exchange; ({existing, Exchange}, _Tx) -> @@ -139,6 +137,9 @@ declare(XName, Type, Durable, AutoDelete, Internal, Args) -> Err end). +map_create_tx(true) -> transaction; +map_create_tx(false) -> none. + store(X = #exchange{name = Name, type = Type}) -> ok = mnesia:write(rabbit_exchange, X, write), case (type_to_module(Type)):serialise_events() of @@ -330,6 +331,12 @@ next_serial(XName) -> #exchange_serial{name = XName, next = Serial + 1}, write), Serial. +peek_serial(XName) -> + case mnesia:read({rabbit_exchange_serial, XName}) of + [#exchange_serial{next = Serial}] -> Serial; + _ -> undefined + end. + %% Used with atoms from records; e.g., the type is expected to exist. type_to_module(T) -> {ok, Module} = rabbit_registry:lookup_module(exchange, T), diff --git a/src/rabbit_router.erl b/src/rabbit_router.erl index 4f683564..b1d940d2 100644 --- a/src/rabbit_router.erl +++ b/src/rabbit_router.erl @@ -84,21 +84,18 @@ match_bindings(SrcName, Match) -> mnesia:async_dirty(fun qlc:e/1, [Query]). match_routing_key(SrcName, [RoutingKey]) -> - MatchHead = #route{binding = #binding{source = SrcName, + find_routes(#route{binding = #binding{source = SrcName, destination = '$1', key = RoutingKey, _ = '_'}}, - mnesia:dirty_select(rabbit_route, [{MatchHead, [], ['$1']}]); + []); match_routing_key(SrcName, [_|_] = RoutingKeys) -> - Condition = list_to_tuple(['orelse' | [{'=:=', '$2', RKey} || - RKey <- RoutingKeys]]), - MatchHead = #route{binding = #binding{source = SrcName, + find_routes(#route{binding = #binding{source = SrcName, destination = '$1', key = '$2', _ = '_'}}, - mnesia:dirty_select(rabbit_route, [{MatchHead, [Condition], ['$1']}]). - - + [list_to_tuple(['orelse' | [{'=:=', '$2', RKey} || + RKey <- RoutingKeys]])]). %%-------------------------------------------------------------------- @@ -119,3 +116,25 @@ lookup_qpids(QNames) -> QPids end end, [], QNames). + +%% Normally we'd call mnesia:dirty_select/2 here, but that is quite +%% expensive due to +%% +%% 1) general mnesia overheads (figuring out table types and +%% locations, etc). We get away with bypassing these because we know +%% that the table +%% - is not the schema table +%% - has a local ram copy +%% - does not have any indices +%% +%% 2) 'fixing' of the table with ets:safe_fixtable/2, which is wholly +%% unnecessary. According to the ets docs (and the code in erl_db.c), +%% 'select' is safe anyway ("Functions that internally traverse over a +%% table, like select and match, will give the same guarantee as +%% safe_fixtable.") and, furthermore, even the lower level iterators +%% ('first' and 'next') are safe on ordered_set tables ("Note that for +%% tables of the ordered_set type, safe_fixtable/2 is not necessary as +%% calls to first/1 and next/2 will always succeed."), which +%% rabbit_route is. +find_routes(MatchHead, Conditions) -> + ets:select(rabbit_route, [{MatchHead, Conditions, ['$1']}]). diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl index 3f4aa54e..f5492cdc 100644 --- a/src/rabbit_tests.erl +++ b/src/rabbit_tests.erl @@ -1072,15 +1072,25 @@ test_user_management() -> control_action(list_permissions, [], [{"-p", "/testhost"}]), {error, {invalid_regexp, _, _}} = control_action(set_permissions, ["guest", "+foo", ".*", ".*"]), + {error, {no_such_user, _}} = + control_action(set_user_tags, ["foo", "bar"]), %% user creation ok = control_action(add_user, ["foo", "bar"]), {error, {user_already_exists, _}} = control_action(add_user, ["foo", "bar"]), ok = control_action(change_password, ["foo", "baz"]), - ok = control_action(set_admin, ["foo"]), - ok = control_action(clear_admin, ["foo"]), - ok = control_action(list_users, []), + + TestTags = fun (Tags) -> + Args = ["foo" | [atom_to_list(T) || T <- Tags]], + ok = control_action(set_user_tags, Args), + {ok, #internal_user{tags = Tags}} = + rabbit_auth_backend_internal:lookup_user(<<"foo">>), + ok = control_action(list_users, []) + end, + TestTags([foo, bar, baz]), + TestTags([administrator]), + TestTags([]), %% vhost creation ok = control_action(add_vhost, ["/testhost"]), @@ -1203,10 +1213,10 @@ test_spawn() -> user(Username) -> #user{username = Username, - is_admin = true, + tags = [administrator], auth_backend = rabbit_auth_backend_internal, impl = #internal_user{username = Username, - is_admin = true}}. + tags = [administrator]}}. test_statistics_event_receiver(Pid) -> receive diff --git a/src/rabbit_types.erl b/src/rabbit_types.erl index aa174e96..22204100 100644 --- a/src/rabbit_types.erl +++ b/src/rabbit_types.erl @@ -140,14 +140,14 @@ -type(user() :: #user{username :: username(), - is_admin :: boolean(), + tags :: [atom()], auth_backend :: atom(), impl :: any()}). -type(internal_user() :: #internal_user{username :: username(), password_hash :: password_hash(), - is_admin :: boolean()}). + tags :: [atom()]}). -type(username() :: binary()). -type(password() :: binary()). diff --git a/src/rabbit_upgrade_functions.erl b/src/rabbit_upgrade_functions.erl index 4b205597..b4ac3328 100644 --- a/src/rabbit_upgrade_functions.erl +++ b/src/rabbit_upgrade_functions.erl @@ -29,6 +29,7 @@ -rabbit_upgrade({semi_durable_route, mnesia, []}). -rabbit_upgrade({exchange_event_serial, mnesia, []}). -rabbit_upgrade({trace_exchanges, mnesia, []}). +-rabbit_upgrade({user_admin_to_tags, mnesia, [user_to_internal_user]}). -rabbit_upgrade({mirror_pids, mnesia, []}). -rabbit_upgrade({gm, mnesia, []}). @@ -45,6 +46,7 @@ -spec(semi_durable_route/0 :: () -> 'ok'). -spec(exchange_event_serial/0 :: () -> 'ok'). -spec(trace_exchanges/0 :: () -> 'ok'). +-spec(user_admin_to_tags/0 :: () -> 'ok'). -spec(mirror_pids/0 :: () -> 'ok'). -spec(gm/0 :: () -> 'ok'). @@ -125,6 +127,16 @@ trace_exchanges() -> VHost <- rabbit_vhost:list()], ok. +user_admin_to_tags() -> + transform( + rabbit_user, + fun({internal_user, Username, PasswordHash, true}) -> + {internal_user, Username, PasswordHash, [administrator]}; + ({internal_user, Username, PasswordHash, false}) -> + {internal_user, Username, PasswordHash, [management]} + end, + [username, password_hash, tags], internal_user). + mirror_pids() -> Tables = [rabbit_queue, rabbit_durable_queue], AddMirrorPidsFun = diff --git a/src/rabbit_vhost.erl b/src/rabbit_vhost.erl index 5270d80b..08d6c99a 100644 --- a/src/rabbit_vhost.erl +++ b/src/rabbit_vhost.erl @@ -91,9 +91,9 @@ delete(VHostPath) -> internal_delete(VHostPath) -> lists:foreach( - fun ({Username, _, _, _}) -> - ok = rabbit_auth_backend_internal:clear_permissions(Username, - VHostPath) + fun (Info) -> + ok = rabbit_auth_backend_internal:clear_permissions( + proplists:get_value(user, Info), VHostPath) end, rabbit_auth_backend_internal:list_vhost_permissions(VHostPath)), ok = mnesia:delete({rabbit_vhost, VHostPath}), |