Merge default into bug19200
This commit is contained in:
commit
26e17f2c24
9
Makefile
9
Makefile
|
|
@ -119,6 +119,7 @@ srcdist: distclean
|
|||
cp codegen.py Makefile dist/$(TARBALL_NAME)
|
||||
|
||||
cp -r scripts dist/$(TARBALL_NAME)
|
||||
cp -r docs dist/$(TARBALL_NAME)
|
||||
chmod 0755 dist/$(TARBALL_NAME)/scripts/*
|
||||
|
||||
(cd dist; tar -zcf $(TARBALL_NAME).tar.gz $(TARBALL_NAME))
|
||||
|
|
@ -133,12 +134,20 @@ distclean: clean
|
|||
install: all
|
||||
@[ -n "$(TARGET_DIR)" ] || (echo "Please set TARGET_DIR."; false)
|
||||
@[ -n "$(SBIN_DIR)" ] || (echo "Please set SBIN_DIR."; false)
|
||||
@[ -n "$(MAN_DIR)" ] || (echo "Please set MAN_DIR."; false)
|
||||
|
||||
$(MAKE) VERSION=$(VERSION) GENERIC_STAGE_DIR=$(TARGET_DIR) generic_stage
|
||||
|
||||
chmod 0755 scripts/*
|
||||
mkdir -p $(SBIN_DIR)
|
||||
mkdir -p $(MAN_DIR)/man1
|
||||
cp scripts/rabbitmq-server $(SBIN_DIR)
|
||||
cp scripts/rabbitmqctl $(SBIN_DIR)
|
||||
cp scripts/rabbitmq-multi $(SBIN_DIR)
|
||||
for manpage in docs/*.pod ; do \
|
||||
pod2man -c "RabbitMQ AMQP Server" -d "" -r "" \
|
||||
$$manpage | gzip --best > \
|
||||
$(MAN_DIR)/man1/`echo $$manpage | sed -e 's:docs/\(.*\)\.pod:\1\.1\.gz:g'`; \
|
||||
done
|
||||
|
||||
rm -f $(TARGET_DIR)/BUILD
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
=head1 NAME
|
||||
|
||||
rabbitmq-multi - start/stop local cluster RabbitMQ nodes
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
rabbitmq-multi I<command> [command option]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
RabbitMQ is an implementation of AMQP, the emerging standard for high
|
||||
performance enterprise messaging. The RabbitMQ server is a robust and
|
||||
scalable implementation of an AMQP broker.
|
||||
|
||||
rabbitmq-multi scripts allows for easy set-up of a cluster on a single
|
||||
machine.
|
||||
|
||||
See also rabbitmq-server(1) for configuration information.
|
||||
|
||||
=head1 COMMANDS
|
||||
|
||||
start_all I<count>
|
||||
start count nodes with unique names, listening on all IP addresses
|
||||
and on sequential ports starting from 5672.
|
||||
|
||||
stop_all
|
||||
stop all local RabbitMQ nodes
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Start 3 local RabbitMQ nodes with unique, sequential port numbers:
|
||||
|
||||
rabbitmq-multi start_all 3
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
rabbitmq-server(1), rabbitmqctl(1)
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Originally written by The RabbitMQ Team <info@lshift.net>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
This package, the RabbitMQ server is licensed under the MPL.
|
||||
|
||||
If you have any questions regarding licensing, please contact us at
|
||||
info@rabbitmq.com.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
RabbitMQ Web Site: http://www.rabbitmq.com
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
=head1 NAME
|
||||
|
||||
rabbitmq-server - start RabbitMQ AMQP server
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
rabbitmq-server [-detached]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
RabbitMQ is an implementation of AMQP, the emerging standard for high
|
||||
performance enterprise messaging. The RabbitMQ server is a robust and
|
||||
scalable implementation of an AMQP broker.
|
||||
|
||||
Running rabbitmq-server in the foreground displays a banner message,
|
||||
and reports on progress in the startup sequence, concluding with the
|
||||
message "broker running", indicating that the RabbitMQ broker has been
|
||||
started successfully. To shut down the server, just terminate the
|
||||
process or use rabbitmqctl(1).
|
||||
|
||||
=head1 ENVIRONMENT
|
||||
|
||||
B<MNESIA_BASE>
|
||||
Defaults to /var/lib/rabbitmq/mnesia. Set this to the directory
|
||||
where Mnesia database files should be placed.
|
||||
|
||||
B<LOG_BASE>
|
||||
Defaults to /var/log/rabbitmq. Log files generated by the server
|
||||
will be placed in this directory.
|
||||
|
||||
B<NODENAME>
|
||||
Defaults to rabbit. This can be useful if you want to run more
|
||||
than one node per machine - B<NODENAME> should be unique per
|
||||
erlang-node-and-machine combination. See clustering on a single
|
||||
machine guide
|
||||
at http://www.rabbitmq.com/clustering.html#single-machine for
|
||||
details.
|
||||
|
||||
B<NODE_IP_ADDRESS>
|
||||
Defaults to 0.0.0.0. This can be changed if you only want to bind
|
||||
to one network interface.
|
||||
|
||||
B<NODE_PORT>
|
||||
Defaults to 5672.
|
||||
|
||||
B<CLUSTER_CONFIG_FILE>
|
||||
Defaults to /etc/default/rabbitmq_cluster.config. If this file is
|
||||
present it is used by the server to auto-configure a RabbitMQ
|
||||
cluster.
|
||||
See the clustering guide at http://www.rabbitmq.com/clustering.html
|
||||
for details.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-detached> start the server process in the background
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Run RabbitMQ AMQP server in the background:
|
||||
|
||||
rabbitmq-server -detached
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
rabbitmq-multi(1), rabbitmqctl(1)
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Originally written by The RabbitMQ Team <info@lshift.net>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
This package, the RabbitMQ server is licensed under the MPL.
|
||||
|
||||
If you have any questions regarding licensing, please contact us at
|
||||
info@rabbitmq.com.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
RabbitMQ Web Site: http://www.rabbitmq.com
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
=head1 NAME
|
||||
|
||||
rabbitmqctl - command line tool for managing a RabbitMQ broker
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
rabbitmqctl [-n I<node>] I<<command>> [command options]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
RabbitMQ is an implementation of AMQP, the emerging standard for high
|
||||
performance enterprise messaging. The RabbitMQ server is a robust and
|
||||
scalable implementation of an AMQP broker.
|
||||
|
||||
rabbitmqctl is a command line tool for managing a RabbitMQ broker.
|
||||
It performs all actions by connecting to one of the broker's nodes.
|
||||
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<-n> I<node>
|
||||
default node is C<rabbit@server>, where server is the local host.
|
||||
On a host named C<server.example.com>, the node name of the RabbitMQ
|
||||
Erlang node will usually be rabbit@server (unless NODENAME has been
|
||||
set to some non-default value at broker startup time).
|
||||
The output of hostname -s is usually the correct suffix to use
|
||||
after the "@" sign. See rabbitmq-server(1) for details of configur-
|
||||
ing the RabbitMQ broker.
|
||||
|
||||
|
||||
=head1 COMMANDS
|
||||
|
||||
=head2 APPLICATION AND CLUSTER MANAGEMENT
|
||||
|
||||
stop
|
||||
stop the Erlang node on which RabbitMQ broker is running.
|
||||
|
||||
stop_app
|
||||
stop the RabbitMQ application, leaving the Erlang node running.
|
||||
This command is typically run prior to performing other management
|
||||
actions that require the RabbitMQ application to be stopped,
|
||||
e.g. I<reset>.
|
||||
|
||||
start_app
|
||||
start the RabbitMQ application.
|
||||
This command is typically run prior to performing other management
|
||||
actions that require the RabbitMQ application to be stopped,
|
||||
e.g. I<reset>.
|
||||
|
||||
status
|
||||
display 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.
|
||||
|
||||
force
|
||||
return a RabbitMQ node to its virgin state.
|
||||
Removes the node from any cluster it belongs to, removes all data
|
||||
from the management database, such as configured users, vhosts and
|
||||
deletes all persistent messages.
|
||||
|
||||
force_reset
|
||||
the same as I<force> command, but resets the node unconditionally,
|
||||
regardless of the current management database state and cluster
|
||||
configuration.
|
||||
It should only be used as a last resort if the database or cluster
|
||||
configuration has been corrupted.
|
||||
|
||||
cluster I<clusternode> ...
|
||||
instruct the node to become member of a cluster with the specified
|
||||
nodes determined by I<clusternode> option(s).
|
||||
See http://www.rabbitmq.com/clustering.html for more information
|
||||
about clustering.
|
||||
|
||||
=head2 USER MANAGEMENT
|
||||
|
||||
add_user I<username> I<password>
|
||||
create a user named I<username> with (initial) password I<password>.
|
||||
|
||||
change_password I<username> I<newpassword>
|
||||
change the password for the user named I<username> to I<newpassword>.
|
||||
|
||||
list_users
|
||||
list all users.
|
||||
|
||||
=head2 ACCESS CONTROL
|
||||
|
||||
add_vhost I<vhostpath>
|
||||
create a new virtual host called I<vhostpath>.
|
||||
|
||||
delete_vhost I<vhostpath>
|
||||
delete a virtual host I<vhostpath>.
|
||||
That command deletes also all its exchanges, queues and user mappings.
|
||||
|
||||
list_vhosts
|
||||
list all virtual hosts.
|
||||
|
||||
map_user_vhost I<username> I<vhostpath>
|
||||
grant the user named I<username> access to the virtual host called
|
||||
I<vhostpath>.
|
||||
|
||||
unmap_user_vhost I<username> I<vhostpath>
|
||||
deny the user named I<username> access to the virtual host called
|
||||
I<vhostpath>.
|
||||
|
||||
list_user_vhost I<username>
|
||||
list all the virtual hosts to which the user named I<username> has
|
||||
been granted access.
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Create a user named foo with (initial) password bar at the Erlang node
|
||||
rabbit@test:
|
||||
|
||||
rabbitmqctl -n rabbit@test add_user foo bar
|
||||
|
||||
Grant user named foo access to the virtual host called test at the
|
||||
default Erlang node:
|
||||
|
||||
rabbitmqctl map_user_vhost foo test
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
rabbitmq-multi(1), rabbitmq-server(1)
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Originally written by The RabbitMQ Team <info@lshift.net>
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
This package, the RabbitMQ server is licensed under the MPL.
|
||||
|
||||
If you have any questions regarding licensing, please contact us at
|
||||
info@rabbitmq.com.
|
||||
|
||||
=head1 REFERENCES
|
||||
|
||||
RabbitMQ Web Site: http://www.rabbitmq.com
|
||||
|
|
@ -25,11 +25,9 @@
|
|||
rabbit_node_monitor,
|
||||
rabbit_persister,
|
||||
rabbit_reader,
|
||||
rabbit_realm,
|
||||
rabbit_router,
|
||||
rabbit_sup,
|
||||
rabbit_tests,
|
||||
rabbit_ticket,
|
||||
rabbit_tracer,
|
||||
rabbit_writer,
|
||||
tcp_acceptor,
|
||||
|
|
|
|||
|
|
@ -27,28 +27,20 @@
|
|||
-record(user_vhost, {username, virtual_host}).
|
||||
|
||||
-record(vhost, {virtual_host, dummy}).
|
||||
-record(vhost_realm, {virtual_host, realm}).
|
||||
|
||||
-record(realm, {name, ignore}).
|
||||
-record(realm_resource, {realm, resource}).
|
||||
|
||||
-record(user_realm, {username, realm, ticket_pattern}).
|
||||
|
||||
-record(realm_visitor, {realm, pid}).
|
||||
|
||||
-record(connection, {user, timeout_sec, frame_max, vhost}).
|
||||
|
||||
-record(content, {class_id,
|
||||
properties, %% either 'none', or a decoded record/tuple
|
||||
properties_bin, %% either 'none', or an encoded properties binary
|
||||
%% Note: at most one of properties and properties_bin can be 'none' at once.
|
||||
payload_fragments_rev %% list of binaries, in reverse order (!)
|
||||
}).
|
||||
-record(content,
|
||||
{class_id,
|
||||
properties, %% either 'none', or a decoded record/tuple
|
||||
properties_bin, %% either 'none', or an encoded properties binary
|
||||
%% Note: at most one of properties and properties_bin can be
|
||||
%% 'none' at once.
|
||||
payload_fragments_rev %% list of binaries, in reverse order (!)
|
||||
}).
|
||||
|
||||
-record(resource, {virtual_host, kind, name}).
|
||||
|
||||
-record(ticket, {realm_name, passive_flag, active_flag, write_flag, read_flag}).
|
||||
|
||||
-record(exchange, {name, type, durable, auto_delete, arguments}).
|
||||
|
||||
-record(amqqueue, {name, durable, auto_delete, arguments, binding_specs, pid}).
|
||||
|
|
@ -80,19 +72,11 @@
|
|||
#resource{virtual_host :: vhost(),
|
||||
kind :: Kind,
|
||||
name :: name()}).
|
||||
-type(realm_name() :: r('realm')).
|
||||
-type(queue_name() :: r('queue')).
|
||||
-type(exchange_name() :: r('exchange')).
|
||||
-type(user() ::
|
||||
#user{username :: username(),
|
||||
password :: password()}).
|
||||
-type(ticket() ::
|
||||
#ticket{realm_name :: realm_name(),
|
||||
passive_flag :: bool(),
|
||||
active_flag :: bool(),
|
||||
write_flag :: bool(),
|
||||
read_flag :: bool()}).
|
||||
-type(permission() :: 'passive' | 'active' | 'write' | 'read').
|
||||
-type(binding_spec() ::
|
||||
#binding_spec{exchange_name :: exchange_name(),
|
||||
routing_key :: routing_key(),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ scalable implementation of an AMQP broker.
|
|||
|
||||
%define _libdir /usr/lib/erlang
|
||||
%define _docdir /usr/share/doc
|
||||
%define _mandir /usr/share/man
|
||||
%define _maindir $RPM_BUILD_ROOT%{_libdir}/lib/rabbitmq_server-%{main_version}
|
||||
%define package_name rabbitmq-server-dist
|
||||
|
||||
|
|
@ -36,8 +37,10 @@ fi
|
|||
%build
|
||||
mkdir %{package_name}
|
||||
mkdir %{package_name}/sbin
|
||||
mkdir %{package_name}/man
|
||||
make install TARGET_DIR=`pwd`/%{package_name} \
|
||||
SBIN_DIR=`pwd`/%{package_name}/sbin \
|
||||
MAN_DIR=`pwd`/%{package_name}/man
|
||||
VERSION=%{main_version}
|
||||
|
||||
%install
|
||||
|
|
@ -45,6 +48,7 @@ mkdir -p %{_maindir}
|
|||
mkdir -p $RPM_BUILD_ROOT%{_docdir}/rabbitmq-server
|
||||
mkdir -p $RPM_BUILD_ROOT/etc/init.d
|
||||
mkdir -p $RPM_BUILD_ROOT/usr/sbin
|
||||
mkdir -p $RPM_BUILD_ROOT%{_mandir}
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT/var/lib/rabbitmq/mnesia
|
||||
mkdir -p $RPM_BUILD_ROOT/var/log/rabbitmq
|
||||
|
|
@ -55,6 +59,7 @@ cp -r %{package_name}/src %{_maindir}
|
|||
cp -r %{package_name}/include %{_maindir}
|
||||
chmod 755 %{package_name}/sbin/*
|
||||
cp %{package_name}/sbin/* $RPM_BUILD_ROOT/usr/sbin/
|
||||
cp -r %{package_name}/man/* $RPM_BUILD_ROOT%{_mandir}/
|
||||
|
||||
cp ../init.d $RPM_BUILD_ROOT/etc/init.d/rabbitmq-server
|
||||
chmod 775 $RPM_BUILD_ROOT/etc/init.d/rabbitmq-server
|
||||
|
|
@ -63,6 +68,8 @@ mv $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl_rea
|
|||
cp ../rabbitmqctl_wrapper $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl
|
||||
chmod 755 $RPM_BUILD_ROOT/usr/sbin/rabbitmqctl
|
||||
|
||||
cp %{buildroot}%{_mandir}/man1/rabbitmqctl.1.gz %{buildroot}%{_mandir}/man1/rabbitmqctl_real.1.gz
|
||||
|
||||
%post
|
||||
# create rabbitmq group
|
||||
if ! getent group rabbitmq >/dev/null; then
|
||||
|
|
@ -107,10 +114,8 @@ fi
|
|||
%defattr(-,root,root)
|
||||
%{_libdir}/lib/rabbitmq_server-%{main_version}/
|
||||
%{_docdir}/rabbitmq-server/
|
||||
/usr/sbin/rabbitmq-server
|
||||
/usr/sbin/rabbitmq-multi
|
||||
/usr/sbin/rabbitmqctl
|
||||
/usr/sbin/rabbitmqctl_real
|
||||
%{_mandir}
|
||||
/usr/sbin
|
||||
/var/lib/rabbitmq
|
||||
/var/log/rabbitmq
|
||||
/etc/init.d/rabbitmq-server
|
||||
|
|
|
|||
|
|
@ -12,4 +12,4 @@ Description: An AMQP server written in Erlang
|
|||
RabbitMQ is an implementation of AMQP, the emerging standard for high
|
||||
performance enterprise messaging. The RabbitMQ server is a robust and
|
||||
scalable implementation of an AMQP broker.
|
||||
Homepage: http://www.rabbitmq.com/
|
||||
Homepage: http://www.rabbitmq.com/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
usr/lib/erlang/lib
|
||||
usr/sbin
|
||||
usr/share/linda/overrides
|
||||
usr/share/man
|
||||
var/lib/rabbitmq/mnesia
|
||||
var/log/rabbitmq
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ include /usr/share/cdbs/1/class/makefile.mk
|
|||
|
||||
RABBIT_LIB=$(DEB_DESTDIR)usr/lib/erlang/lib/rabbitmq_server-$(DEB_UPSTREAM_VERSION)
|
||||
|
||||
DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB)/ SBIN_DIR=$(DEB_DESTDIR)usr/sbin
|
||||
DEB_MAKE_INSTALL_TARGET := install TARGET_DIR=$(RABBIT_LIB)/ SBIN_DIR=$(DEB_DESTDIR)usr/sbin MAN_DIR=$(DEB_DESTDIR)usr/share/man
|
||||
|
||||
DOCDIR=$(DEB_DESTDIR)usr/share/doc/rabbitmq-server/
|
||||
|
||||
|
|
@ -14,5 +14,5 @@ install/rabbitmq-server::
|
|||
rm $(RABBIT_LIB)/LICENSE*
|
||||
mv $(DEB_DESTDIR)usr/sbin/rabbitmqctl $(DEB_DESTDIR)usr/sbin/rabbitmqctl_real
|
||||
cp debian/rabbitmqctl_wrapper $(DEB_DESTDIR)usr/sbin/rabbitmqctl
|
||||
cp $(DEB_DESTDIR)usr/share/man/man1/rabbitmqctl.1.gz $(DEB_DESTDIR)usr/share/man/man1/rabbitmqctl_real.1.gz
|
||||
chmod a+x $(DEB_DESTDIR)usr/sbin/rabbitmqctl
|
||||
echo "Tag: usr-lib-in-arch-all" > $(DEB_DESTDIR)usr/share/linda/overrides/rabbitmq-server
|
||||
|
|
|
|||
|
|
@ -7,11 +7,10 @@ dist:
|
|||
make -C ../.. VERSION=$(VERSION) srcdist
|
||||
tar -zxvf ../../dist/$(SOURCE_DIR).tar.gz
|
||||
|
||||
mkdir $(TARGET_DIR)
|
||||
mkdir $(TARGET_DIR)/sbin
|
||||
make -C $(SOURCE_DIR) \
|
||||
TARGET_DIR=`pwd`/$(TARGET_DIR) \
|
||||
SBIN_DIR=`pwd`/$(TARGET_DIR)/sbin \
|
||||
MAN_DIR=`pwd`/$(TARGET_DIR)/share/man \
|
||||
install
|
||||
|
||||
tar -zcf $(TARGET_TARBALL).tar.gz $(TARGET_DIR)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ dist:
|
|||
rm -rf $(SOURCE_DIR)/scripts
|
||||
rm -rf $(SOURCE_DIR)/codegen* $(SOURCE_DIR)/Makefile
|
||||
rm -f $(SOURCE_DIR)/BUILD
|
||||
rm -rf $(SOURCE_DIR)/docs
|
||||
|
||||
mv $(SOURCE_DIR) $(TARGET_DIR)
|
||||
zip -r $(TARGET_ZIP).zip $(TARGET_DIR)
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) ->
|
|||
end
|
||||
end, [], Apps),
|
||||
ok.
|
||||
|
||||
|
||||
start_applications(Apps) ->
|
||||
manage_applications(fun lists:foldl/3,
|
||||
fun application:start/1,
|
||||
|
|
@ -133,9 +133,9 @@ start(normal, []) ->
|
|||
io:format("starting ~-20s ...", [Msg]),
|
||||
Thunk(),
|
||||
io:format("done~n");
|
||||
({Msg, M, F, A}) ->
|
||||
({Msg, M, F, A}) ->
|
||||
io:format("starting ~-20s ...", [Msg]),
|
||||
apply(M, F, A),
|
||||
apply(M, F, A),
|
||||
io:format("done~n")
|
||||
end,
|
||||
[{"database",
|
||||
|
|
@ -155,14 +155,12 @@ start(normal, []) ->
|
|||
{"recovery",
|
||||
fun () ->
|
||||
ok = maybe_insert_default_data(),
|
||||
|
||||
ok = rabbit_exchange:recover(),
|
||||
ok = rabbit_amqqueue:recover(),
|
||||
ok = rabbit_realm:recover()
|
||||
ok = rabbit_amqqueue:recover()
|
||||
end},
|
||||
{"persister",
|
||||
fun () ->
|
||||
ok = start_child(rabbit_persister)
|
||||
fun () ->
|
||||
ok = start_child(rabbit_persister)
|
||||
end},
|
||||
{"builtin applications",
|
||||
fun () ->
|
||||
|
|
@ -220,26 +218,8 @@ insert_default_data() ->
|
|||
{ok, DefaultPass} = application:get_env(default_pass),
|
||||
{ok, DefaultVHost} = application:get_env(default_vhost),
|
||||
ok = rabbit_access_control:add_vhost(DefaultVHost),
|
||||
ok = insert_default_user(DefaultUser, DefaultPass,
|
||||
[{DefaultVHost, [<<"/data">>, <<"/admin">>]}]),
|
||||
ok.
|
||||
|
||||
insert_default_user(Username, Password, VHostSpecs) ->
|
||||
ok = rabbit_access_control:add_user(Username, Password),
|
||||
lists:foreach(
|
||||
fun ({VHostPath, Realms}) ->
|
||||
ok = rabbit_access_control:map_user_vhost(
|
||||
Username, VHostPath),
|
||||
lists:foreach(
|
||||
fun (Realm) ->
|
||||
RealmFullName =
|
||||
rabbit_misc:r(VHostPath, realm, Realm),
|
||||
ok = rabbit_access_control:map_user_realm(
|
||||
Username,
|
||||
rabbit_access_control:full_ticket(
|
||||
RealmFullName))
|
||||
end, Realms)
|
||||
end, VHostSpecs),
|
||||
ok = rabbit_access_control:add_user(DefaultUser, DefaultPass),
|
||||
ok = rabbit_access_control:map_user_vhost(DefaultUser, DefaultVHost),
|
||||
ok.
|
||||
|
||||
start_builtin_amq_applications() ->
|
||||
|
|
@ -278,7 +258,7 @@ error_log_location() ->
|
|||
end.
|
||||
|
||||
sasl_log_location() ->
|
||||
case application:get_env(sasl, sasl_error_logger) of
|
||||
case application:get_env(sasl, sasl_error_logger) of
|
||||
{ok, {file, File}} -> File;
|
||||
{ok, false} -> undefined;
|
||||
{ok, tty} -> tty;
|
||||
|
|
|
|||
|
|
@ -28,12 +28,11 @@
|
|||
-include("rabbit.hrl").
|
||||
|
||||
-export([check_login/2, user_pass_login/2,
|
||||
check_vhost_access/2, lookup_realm_access/2]).
|
||||
check_vhost_access/2]).
|
||||
-export([add_user/2, delete_user/1, change_password/2, list_users/0,
|
||||
lookup_user/1]).
|
||||
-export([add_vhost/1, delete_vhost/1, list_vhosts/0, list_vhost_users/1]).
|
||||
-export([list_user_vhosts/1, map_user_vhost/2, unmap_user_vhost/2]).
|
||||
-export([list_user_realms/2, map_user_realm/2, full_ticket/1]).
|
||||
|
||||
%%----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -42,7 +41,6 @@
|
|||
-spec(check_login/2 :: (binary(), binary()) -> user()).
|
||||
-spec(user_pass_login/2 :: (username(), password()) -> user()).
|
||||
-spec(check_vhost_access/2 :: (user(), vhost()) -> 'ok').
|
||||
-spec(lookup_realm_access/2 :: (user(), realm_name()) -> maybe(ticket())).
|
||||
-spec(add_user/2 :: (username(), password()) -> 'ok').
|
||||
-spec(delete_user/1 :: (username()) -> 'ok').
|
||||
-spec(change_password/2 :: (username(), password()) -> 'ok').
|
||||
|
|
@ -55,9 +53,6 @@
|
|||
-spec(list_user_vhosts/1 :: (username()) -> [vhost()]).
|
||||
-spec(map_user_vhost/2 :: (username(), vhost()) -> 'ok').
|
||||
-spec(unmap_user_vhost/2 :: (username(), vhost()) -> 'ok').
|
||||
-spec(map_user_realm/2 :: (username(), ticket()) -> 'ok').
|
||||
-spec(list_user_realms/2 :: (username(), vhost()) -> [{name(), ticket()}]).
|
||||
-spec(full_ticket/1 :: (realm_name()) -> ticket()).
|
||||
|
||||
-endif.
|
||||
|
||||
|
|
@ -87,7 +82,7 @@ check_login(<<"AMQPLAIN">>, Response) ->
|
|||
[LoginTable])
|
||||
end;
|
||||
|
||||
check_login(Mechanism, _Response) ->
|
||||
check_login(Mechanism, _Response) ->
|
||||
rabbit_misc:protocol_error(
|
||||
access_refused, "unsupported authentication mechanism '~s'",
|
||||
[Mechanism]).
|
||||
|
|
@ -130,18 +125,6 @@ check_vhost_access(#user{username = Username}, VHostPath) ->
|
|||
[VHostPath, Username])
|
||||
end.
|
||||
|
||||
lookup_realm_access(#user{username = Username}, RealmName = #resource{kind = realm}) ->
|
||||
%% TODO: use dirty ops instead
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
case user_realms(Username, RealmName) of
|
||||
[] ->
|
||||
none;
|
||||
[#user_realm{ticket_pattern = TicketPattern}] ->
|
||||
TicketPattern
|
||||
end
|
||||
end).
|
||||
|
||||
add_user(Username, Password) ->
|
||||
R = rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
|
|
@ -162,8 +145,7 @@ delete_user(Username) ->
|
|||
Username,
|
||||
fun () ->
|
||||
ok = mnesia:delete({user, Username}),
|
||||
ok = mnesia:delete({user_vhost, Username}),
|
||||
ok = mnesia:delete({user_realm, Username})
|
||||
ok = mnesia:delete({user_vhost, Username})
|
||||
end)),
|
||||
rabbit_log:info("Deleted user ~p~n", [Username]),
|
||||
R.
|
||||
|
|
@ -191,24 +173,14 @@ add_vhost(VHostPath) ->
|
|||
case mnesia:read({vhost, VHostPath}) of
|
||||
[] ->
|
||||
ok = mnesia:write(#vhost{virtual_host = VHostPath}),
|
||||
DataRealm =
|
||||
rabbit_misc:r(VHostPath, realm, <<"/data">>),
|
||||
AdminRealm =
|
||||
rabbit_misc:r(VHostPath, realm, <<"/admin">>),
|
||||
ok = rabbit_realm:add_realm(DataRealm),
|
||||
ok = rabbit_realm:add_realm(AdminRealm),
|
||||
#exchange{} = rabbit_exchange:declare(
|
||||
DataRealm, <<"">>,
|
||||
direct, true, false, []),
|
||||
#exchange{} = rabbit_exchange:declare(
|
||||
DataRealm, <<"amq.direct">>,
|
||||
direct, true, false, []),
|
||||
#exchange{} = rabbit_exchange:declare(
|
||||
DataRealm, <<"amq.topic">>,
|
||||
topic, true, false, []),
|
||||
#exchange{} = rabbit_exchange:declare(
|
||||
DataRealm, <<"amq.fanout">>,
|
||||
fanout, true, false, []),
|
||||
[rabbit_exchange:declare(
|
||||
rabbit_misc:r(VHostPath, exchange, Name),
|
||||
Type, true, false, []) ||
|
||||
{Name,Type} <-
|
||||
[{<<"">>, direct},
|
||||
{<<"amq.direct">>, direct},
|
||||
{<<"amq.topic">>, topic},
|
||||
{<<"amq.fanout">>, fanout}]],
|
||||
ok;
|
||||
[_] ->
|
||||
mnesia:abort({vhost_already_exists, VHostPath})
|
||||
|
|
@ -240,11 +212,6 @@ internal_delete_vhost(VHostPath) ->
|
|||
ok = rabbit_exchange:delete(Name, false)
|
||||
end,
|
||||
rabbit_exchange:list_vhost_exchanges(VHostPath)),
|
||||
lists:foreach(fun (RealmName) ->
|
||||
ok = rabbit_realm:delete_realm(
|
||||
rabbit_misc:r(VHostPath, realm, RealmName))
|
||||
end,
|
||||
rabbit_realm:list_vhost_realms(VHostPath)),
|
||||
lists:foreach(fun (Username) ->
|
||||
ok = unmap_user_vhost(Username, VHostPath)
|
||||
end,
|
||||
|
|
@ -290,77 +257,8 @@ unmap_user_vhost(Username, VHostPath) ->
|
|||
rabbit_misc:with_user_and_vhost(
|
||||
Username, VHostPath,
|
||||
fun () ->
|
||||
lists:foreach(fun mnesia:delete_object/1,
|
||||
user_realms(Username,
|
||||
rabbit_misc:r(VHostPath, realm))),
|
||||
ok = mnesia:delete_object(
|
||||
#user_vhost{username = Username,
|
||||
virtual_host = VHostPath})
|
||||
end)).
|
||||
|
||||
map_user_realm(Username,
|
||||
Ticket = #ticket{realm_name = RealmName =
|
||||
#resource{virtual_host = VHostPath,
|
||||
kind = realm}}) ->
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
rabbit_misc:with_user_and_vhost(
|
||||
Username, VHostPath,
|
||||
rabbit_misc:with_realm(
|
||||
RealmName,
|
||||
fun () ->
|
||||
lists:foreach(fun mnesia:delete_object/1,
|
||||
user_realms(Username, RealmName)),
|
||||
case internal_lookup_vhost_access(Username, VHostPath) of
|
||||
{ok, _R} ->
|
||||
case ticket_liveness(Ticket) of
|
||||
alive ->
|
||||
ok = mnesia:write(
|
||||
#user_realm{username = Username,
|
||||
realm = RealmName,
|
||||
ticket_pattern = Ticket});
|
||||
dead ->
|
||||
ok
|
||||
end;
|
||||
not_found ->
|
||||
mnesia:abort(not_mapped_to_vhost)
|
||||
end
|
||||
end))).
|
||||
|
||||
list_user_realms(Username, VHostPath) ->
|
||||
[{Name, Pattern} ||
|
||||
#user_realm{realm = #resource{name = Name},
|
||||
ticket_pattern = Pattern} <-
|
||||
%% TODO: use dirty ops instead
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
rabbit_misc:with_user_and_vhost(
|
||||
Username, VHostPath,
|
||||
fun () ->
|
||||
case internal_lookup_vhost_access(
|
||||
Username, VHostPath) of
|
||||
{ok, _R} ->
|
||||
user_realms(Username,
|
||||
rabbit_misc:r(VHostPath, realm));
|
||||
not_found ->
|
||||
mnesia:abort(not_mapped_to_vhost)
|
||||
end
|
||||
end))].
|
||||
|
||||
ticket_liveness(#ticket{passive_flag = false,
|
||||
active_flag = false,
|
||||
write_flag = false,
|
||||
read_flag = false}) ->
|
||||
dead;
|
||||
ticket_liveness(_) ->
|
||||
alive.
|
||||
|
||||
full_ticket(RealmName) ->
|
||||
#ticket{realm_name = RealmName,
|
||||
passive_flag = true,
|
||||
active_flag = true,
|
||||
write_flag = true,
|
||||
read_flag = true}.
|
||||
|
||||
user_realms(Username, RealmName) ->
|
||||
mnesia:match_object(#user_realm{username = Username,
|
||||
realm = RealmName,
|
||||
_ = '_'}).
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
-module(rabbit_amqqueue).
|
||||
|
||||
-export([start/0, recover/0, declare/5, delete/3, purge/1, internal_delete/1]).
|
||||
-export([pseudo_queue/3]).
|
||||
-export([start/0, recover/0, declare/4, delete/3, purge/1, internal_delete/1]).
|
||||
-export([pseudo_queue/2]).
|
||||
-export([lookup/1, with/2, with_or_die/2, list_vhost_queues/1,
|
||||
stat/1, stat_all/0, deliver/5, redeliver/2, requeue/3, ack/4,
|
||||
commit/2, rollback/2]).
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
{'error', 'queue_not_found' | 'exchange_not_found'}).
|
||||
-spec(start/0 :: () -> 'ok').
|
||||
-spec(recover/0 :: () -> 'ok').
|
||||
-spec(declare/5 :: (realm_name(), name(), bool(), bool(), amqp_table()) ->
|
||||
-spec(declare/4 :: (queue_name(), bool(), bool(), amqp_table()) ->
|
||||
amqqueue()).
|
||||
-spec(add_binding/4 ::
|
||||
(queue_name(), exchange_name(), routing_key(), amqp_table()) ->
|
||||
|
|
@ -96,7 +96,7 @@
|
|||
-spec(notify_sent/2 :: (pid(), pid()) -> 'ok').
|
||||
-spec(internal_delete/1 :: (queue_name()) -> 'ok' | not_found()).
|
||||
-spec(on_node_down/1 :: (node()) -> 'ok').
|
||||
-spec(pseudo_queue/3 :: (realm_name(), binary(), pid()) -> amqqueue()).
|
||||
-spec(pseudo_queue/2 :: (binary(), pid()) -> amqqueue()).
|
||||
|
||||
-endif.
|
||||
|
||||
|
|
@ -130,9 +130,8 @@ recover_durable_queues() ->
|
|||
ok
|
||||
end).
|
||||
|
||||
declare(RealmName, NameBin, Durable, AutoDelete, Args) ->
|
||||
QName = rabbit_misc:r(RealmName, queue, NameBin),
|
||||
Q = start_queue_process(#amqqueue{name = QName,
|
||||
declare(QueueName, Durable, AutoDelete, Args) ->
|
||||
Q = start_queue_process(#amqqueue{name = QueueName,
|
||||
durable = Durable,
|
||||
auto_delete = AutoDelete,
|
||||
arguments = Args,
|
||||
|
|
@ -140,9 +139,8 @@ declare(RealmName, NameBin, Durable, AutoDelete, Args) ->
|
|||
pid = none}),
|
||||
case rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
case mnesia:wread({amqqueue, QName}) of
|
||||
case mnesia:wread({amqqueue, QueueName}) of
|
||||
[] -> ok = recover_queue(Q),
|
||||
ok = rabbit_realm:add(RealmName, QName),
|
||||
Q;
|
||||
[ExistingQ] -> ExistingQ
|
||||
end
|
||||
|
|
@ -251,7 +249,7 @@ with(Name, F, E) ->
|
|||
end.
|
||||
|
||||
with(Name, F) ->
|
||||
with(Name, F, fun () -> {error, not_found} end).
|
||||
with(Name, F, fun () -> {error, not_found} end).
|
||||
with_or_die(Name, F) ->
|
||||
with(Name, F, fun () -> rabbit_misc:protocol_error(
|
||||
not_found, "no ~s", [rabbit_misc:rs(Name)])
|
||||
|
|
@ -338,28 +336,20 @@ internal_delete(QueueName) ->
|
|||
case mnesia:wread({amqqueue, QueueName}) of
|
||||
[] -> {error, not_found};
|
||||
[Q] ->
|
||||
ok = delete_temp(Q),
|
||||
ok = delete_queue(Q),
|
||||
ok = mnesia:delete({durable_queues, QueueName}),
|
||||
ok = rabbit_realm:delete_from_all(QueueName),
|
||||
ok
|
||||
end
|
||||
end).
|
||||
|
||||
delete_temp(Q = #amqqueue{name = QueueName}) ->
|
||||
delete_queue(Q = #amqqueue{name = QueueName}) ->
|
||||
ok = delete_bindings(Q),
|
||||
ok = rabbit_exchange:delete_binding(
|
||||
default_binding_spec(QueueName), Q),
|
||||
ok = mnesia:delete({amqqueue, QueueName}),
|
||||
ok.
|
||||
|
||||
delete_queue(Q = #amqqueue{name = QueueName, durable = Durable}) ->
|
||||
ok = delete_temp(Q),
|
||||
if
|
||||
Durable -> ok;
|
||||
true -> ok = rabbit_realm:delete_from_all(QueueName)
|
||||
end.
|
||||
|
||||
on_node_down(Node) ->
|
||||
on_node_down(Node) ->
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
qlc:fold(
|
||||
|
|
@ -370,8 +360,8 @@ on_node_down(Node) ->
|
|||
node(Pid) == Node]))
|
||||
end).
|
||||
|
||||
pseudo_queue(RealmName, NameBin, Pid) ->
|
||||
#amqqueue{name = rabbit_misc:r(RealmName, queue, NameBin),
|
||||
pseudo_queue(QueueName, Pid) ->
|
||||
#amqqueue{name = QueueName,
|
||||
durable = false,
|
||||
auto_delete = false,
|
||||
arguments = [],
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
transaction_id, tx_participants, next_tag,
|
||||
uncommitted_ack_q, unacked_message_q,
|
||||
username, virtual_host,
|
||||
most_recently_declared_queue, consumer_mapping, next_ticket}).
|
||||
most_recently_declared_queue, consumer_mapping}).
|
||||
|
||||
%%----------------------------------------------------------------------------
|
||||
|
||||
|
|
@ -94,8 +94,7 @@ init(ProxyPid, [ReaderPid, WriterPid, Username, VHost]) ->
|
|||
username = Username,
|
||||
virtual_host = VHost,
|
||||
most_recently_declared_queue = <<>>,
|
||||
consumer_mapping = dict:new(),
|
||||
next_ticket = 101}.
|
||||
consumer_mapping = dict:new()}.
|
||||
|
||||
handle_message({method, Method, Content}, State) ->
|
||||
case (catch handle_method(Method, Content, State)) of
|
||||
|
|
@ -140,7 +139,6 @@ handle_message(Other, State) ->
|
|||
|
||||
terminate(Reason, State = #ch{writer_pid = WriterPid}) ->
|
||||
Res = notify_queues(internal_rollback(State)),
|
||||
ok = rabbit_realm:leave_realms(self()),
|
||||
case Reason of
|
||||
normal -> ok = Res;
|
||||
_ -> ok
|
||||
|
|
@ -195,14 +193,6 @@ die_precondition_failed(Fmt, Params) ->
|
|||
rabbit_misc:protocol_error({false, 406, <<"PRECONDITION_FAILED">>},
|
||||
Fmt, Params).
|
||||
|
||||
check_ticket(TicketNumber, FieldIndex, Name, #ch{ username = Username}) ->
|
||||
rabbit_ticket:check_ticket(TicketNumber, FieldIndex, Name, Username).
|
||||
|
||||
lookup_ticket(TicketNumber, FieldIndex,
|
||||
#ch{ username = Username, virtual_host = VHostPath }) ->
|
||||
rabbit_ticket:lookup_ticket(TicketNumber, FieldIndex,
|
||||
Username, VHostPath).
|
||||
|
||||
%% check that an exchange/queue name does not contain the reserved
|
||||
%% "amq." prefix.
|
||||
%%
|
||||
|
|
@ -235,57 +225,19 @@ handle_method(_Method, _, #ch{state = starting}) ->
|
|||
|
||||
handle_method(#'channel.close'{}, _, State = #ch{writer_pid = WriterPid}) ->
|
||||
ok = notify_queues(internal_rollback(State)),
|
||||
ok = rabbit_realm:leave_realms(self()),
|
||||
ok = rabbit_writer:send_command(WriterPid, #'channel.close_ok'{}),
|
||||
ok = rabbit_writer:shutdown(WriterPid),
|
||||
stop;
|
||||
|
||||
handle_method(#'access.request'{realm = RealmNameBin,
|
||||
exclusive = Exclusive,
|
||||
passive = Passive,
|
||||
active = Active,
|
||||
write = Write,
|
||||
read = Read},
|
||||
_, State = #ch{username = Username,
|
||||
virtual_host = VHostPath,
|
||||
next_ticket = NextTicket}) ->
|
||||
RealmName = rabbit_misc:r(VHostPath, realm, RealmNameBin),
|
||||
Ticket = #ticket{realm_name = RealmName,
|
||||
passive_flag = Passive,
|
||||
active_flag = Active,
|
||||
write_flag = Write,
|
||||
read_flag = Read},
|
||||
case rabbit_realm:access_request(Username, Exclusive, Ticket) of
|
||||
ok ->
|
||||
rabbit_ticket:record_ticket(NextTicket, Ticket),
|
||||
NewState = State#ch{next_ticket = NextTicket + 1},
|
||||
{reply, #'access.request_ok'{ticket = NextTicket}, NewState};
|
||||
{error, not_found} ->
|
||||
rabbit_misc:protocol_error(
|
||||
invalid_path, "no ~s", [rabbit_misc:rs(RealmName)]);
|
||||
{error, bad_realm_path} ->
|
||||
%% FIXME: spec bug? access_refused is a soft error, spec requires it to be hard
|
||||
rabbit_misc:protocol_error(
|
||||
access_refused, "bad path for ~s", [rabbit_misc:rs(RealmName)]);
|
||||
{error, resource_locked} ->
|
||||
rabbit_misc:protocol_error(
|
||||
resource_locked, "~s is locked", [rabbit_misc:rs(RealmName)]);
|
||||
{error, access_refused} ->
|
||||
rabbit_misc:protocol_error(
|
||||
access_refused,
|
||||
"~w permissions denied for user '~s' attempting to access ~s",
|
||||
[rabbit_misc:permission_list(Ticket),
|
||||
Username, rabbit_misc:rs(RealmName)])
|
||||
end;
|
||||
handle_method(#'access.request'{},_, State) ->
|
||||
{reply, #'access.request_ok'{ticket = 1}, State};
|
||||
|
||||
handle_method(#'basic.publish'{ticket = TicketNumber,
|
||||
exchange = ExchangeNameBin,
|
||||
handle_method(#'basic.publish'{exchange = ExchangeNameBin,
|
||||
routing_key = RoutingKey,
|
||||
mandatory = Mandatory,
|
||||
immediate = Immediate},
|
||||
Content, State = #ch{ virtual_host = VHostPath}) ->
|
||||
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
|
||||
check_ticket(TicketNumber, #ticket.write_flag, ExchangeName, State),
|
||||
Exchange = rabbit_exchange:lookup_or_die(ExchangeName),
|
||||
%% We decode the content's properties here because we're almost
|
||||
%% certain to want to look at delivery-mode and priority.
|
||||
|
|
@ -323,13 +275,11 @@ handle_method(#'basic.ack'{delivery_tag = DeliveryTag,
|
|||
uncommitted_ack_q = NewUAQ})
|
||||
end};
|
||||
|
||||
handle_method(#'basic.get'{ticket = TicketNumber,
|
||||
queue = QueueNameBin,
|
||||
handle_method(#'basic.get'{queue = QueueNameBin,
|
||||
no_ack = NoAck},
|
||||
_, State = #ch{ proxy_pid = ProxyPid, writer_pid = WriterPid,
|
||||
next_tag = DeliveryTag }) ->
|
||||
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
|
||||
check_ticket(TicketNumber, #ticket.read_flag, QueueName, State),
|
||||
case rabbit_amqqueue:with_or_die(
|
||||
QueueName,
|
||||
fun (Q) -> rabbit_amqqueue:basic_get(Q, ProxyPid, NoAck) end) of
|
||||
|
|
@ -352,8 +302,7 @@ handle_method(#'basic.get'{ticket = TicketNumber,
|
|||
{reply, #'basic.get_empty'{cluster_id = <<>>}, State}
|
||||
end;
|
||||
|
||||
handle_method(#'basic.consume'{ticket = TicketNumber,
|
||||
queue = QueueNameBin,
|
||||
handle_method(#'basic.consume'{queue = QueueNameBin,
|
||||
consumer_tag = ConsumerTag,
|
||||
no_local = _, % FIXME: implement
|
||||
no_ack = NoAck,
|
||||
|
|
@ -365,7 +314,6 @@ handle_method(#'basic.consume'{ticket = TicketNumber,
|
|||
case dict:find(ConsumerTag, ConsumerMapping) of
|
||||
error ->
|
||||
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
|
||||
check_ticket(TicketNumber, #ticket.read_flag, QueueName, State),
|
||||
ActualConsumerTag =
|
||||
case ConsumerTag of
|
||||
<<>> -> rabbit_misc:binstring_guid("amq.ctag");
|
||||
|
|
@ -391,7 +339,7 @@ handle_method(#'basic.consume'{ticket = TicketNumber,
|
|||
ConsumerMapping)}};
|
||||
{error, queue_owned_by_another_connection} ->
|
||||
%% The spec is silent on which exception to use
|
||||
%% here. This seems reasonable?
|
||||
%% here. This seems reasonable?
|
||||
%% FIXME: check this
|
||||
|
||||
rabbit_misc:protocol_error(
|
||||
|
|
@ -495,8 +443,7 @@ handle_method(#'basic.recover'{}, _, _State) ->
|
|||
rabbit_misc:protocol_error(
|
||||
not_allowed, "attempt to recover a transactional channel",[]);
|
||||
|
||||
handle_method(#'exchange.declare'{ticket = TicketNumber,
|
||||
exchange = ExchangeNameBin,
|
||||
handle_method(#'exchange.declare'{exchange = ExchangeNameBin,
|
||||
type = TypeNameBin,
|
||||
passive = false,
|
||||
durable = Durable,
|
||||
|
|
@ -505,17 +452,13 @@ handle_method(#'exchange.declare'{ticket = TicketNumber,
|
|||
nowait = NoWait,
|
||||
arguments = Args},
|
||||
_, State = #ch{ virtual_host = VHostPath }) ->
|
||||
#ticket{realm_name = RealmName} =
|
||||
lookup_ticket(TicketNumber, #ticket.active_flag, State),
|
||||
CheckedType = rabbit_exchange:check_type(TypeNameBin),
|
||||
%% FIXME: clarify spec as per declare wrt differing realms
|
||||
X = case rabbit_exchange:lookup(
|
||||
rabbit_misc:r(VHostPath, exchange, ExchangeNameBin)) of
|
||||
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
|
||||
X = case rabbit_exchange:lookup(ExchangeName) of
|
||||
{ok, FoundX} -> FoundX;
|
||||
{error, not_found} ->
|
||||
ActualNameBin = check_name('exchange', ExchangeNameBin),
|
||||
rabbit_exchange:declare(RealmName,
|
||||
ActualNameBin,
|
||||
check_name('exchange', ExchangeNameBin),
|
||||
rabbit_exchange:declare(ExchangeName,
|
||||
CheckedType,
|
||||
Durable,
|
||||
AutoDelete,
|
||||
|
|
@ -524,26 +467,21 @@ handle_method(#'exchange.declare'{ticket = TicketNumber,
|
|||
ok = rabbit_exchange:assert_type(X, CheckedType),
|
||||
return_ok(State, NoWait, #'exchange.declare_ok'{});
|
||||
|
||||
handle_method(#'exchange.declare'{ticket = TicketNumber,
|
||||
exchange = ExchangeNameBin,
|
||||
handle_method(#'exchange.declare'{exchange = ExchangeNameBin,
|
||||
type = TypeNameBin,
|
||||
passive = true,
|
||||
nowait = NoWait},
|
||||
_, State = #ch{ virtual_host = VHostPath }) ->
|
||||
%% FIXME: spec issue: permit active_flag here as well as passive_flag?
|
||||
#ticket{} = lookup_ticket(TicketNumber, #ticket.passive_flag, State),
|
||||
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
|
||||
X = rabbit_exchange:lookup_or_die(ExchangeName),
|
||||
ok = rabbit_exchange:assert_type(X, rabbit_exchange:check_type(TypeNameBin)),
|
||||
return_ok(State, NoWait, #'exchange.declare_ok'{});
|
||||
|
||||
handle_method(#'exchange.delete'{ticket = TicketNumber,
|
||||
exchange = ExchangeNameBin,
|
||||
handle_method(#'exchange.delete'{exchange = ExchangeNameBin,
|
||||
if_unused = IfUnused,
|
||||
nowait = NoWait},
|
||||
_, State = #ch { virtual_host = VHostPath }) ->
|
||||
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
|
||||
check_ticket(TicketNumber, #ticket.active_flag, ExchangeName, State),
|
||||
case rabbit_exchange:delete(ExchangeName, IfUnused) of
|
||||
{error, not_found} ->
|
||||
rabbit_misc:protocol_error(
|
||||
|
|
@ -555,8 +493,7 @@ handle_method(#'exchange.delete'{ticket = TicketNumber,
|
|||
return_ok(State, NoWait, #'exchange.delete_ok'{})
|
||||
end;
|
||||
|
||||
handle_method(#'queue.declare'{ticket = TicketNumber,
|
||||
queue = QueueNameBin,
|
||||
handle_method(#'queue.declare'{queue = QueueNameBin,
|
||||
passive = false,
|
||||
durable = Durable,
|
||||
exclusive = ExclusiveDeclare,
|
||||
|
|
@ -565,8 +502,6 @@ handle_method(#'queue.declare'{ticket = TicketNumber,
|
|||
arguments = Args},
|
||||
_, State = #ch { virtual_host = VHostPath,
|
||||
reader_pid = ReaderPid }) ->
|
||||
#ticket{realm_name = RealmName} =
|
||||
lookup_ticket(TicketNumber, #ticket.active_flag, State),
|
||||
%% FIXME: atomic create&claim
|
||||
Finish =
|
||||
fun (Q) ->
|
||||
|
|
@ -587,7 +522,6 @@ handle_method(#'queue.declare'{ticket = TicketNumber,
|
|||
end,
|
||||
Q
|
||||
end,
|
||||
%% FIXME: clarify spec as per declare wrt differing realms
|
||||
Q = case rabbit_amqqueue:with(
|
||||
rabbit_misc:r(VHostPath, queue, QueueNameBin),
|
||||
Finish) of
|
||||
|
|
@ -597,34 +531,28 @@ handle_method(#'queue.declare'{ticket = TicketNumber,
|
|||
<<>> -> rabbit_misc:binstring_guid("amq.gen");
|
||||
Other -> check_name('queue', Other)
|
||||
end,
|
||||
Finish(rabbit_amqqueue:declare(RealmName,
|
||||
ActualNameBin,
|
||||
Durable,
|
||||
AutoDelete,
|
||||
Args));
|
||||
QueueName = rabbit_misc:r(VHostPath, queue, ActualNameBin),
|
||||
Finish(rabbit_amqqueue:declare(QueueName,
|
||||
Durable, AutoDelete, Args));
|
||||
Other -> Other
|
||||
end,
|
||||
return_queue_declare_ok(State, NoWait, Q);
|
||||
|
||||
handle_method(#'queue.declare'{ticket = TicketNumber,
|
||||
queue = QueueNameBin,
|
||||
handle_method(#'queue.declare'{queue = QueueNameBin,
|
||||
passive = true,
|
||||
nowait = NoWait},
|
||||
_, State = #ch{ virtual_host = VHostPath }) ->
|
||||
#ticket{} = lookup_ticket(TicketNumber, #ticket.passive_flag, State),
|
||||
QueueName = rabbit_misc:r(VHostPath, queue, QueueNameBin),
|
||||
Q = rabbit_amqqueue:with_or_die(QueueName, fun (Q) -> Q end),
|
||||
return_queue_declare_ok(State, NoWait, Q);
|
||||
|
||||
handle_method(#'queue.delete'{ticket = TicketNumber,
|
||||
queue = QueueNameBin,
|
||||
handle_method(#'queue.delete'{queue = QueueNameBin,
|
||||
if_unused = IfUnused,
|
||||
if_empty = IfEmpty,
|
||||
nowait = NoWait
|
||||
},
|
||||
_, State) ->
|
||||
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
|
||||
check_ticket(TicketNumber, #ticket.active_flag, QueueName, State),
|
||||
case rabbit_amqqueue:with_or_die(
|
||||
QueueName,
|
||||
fun (Q) -> rabbit_amqqueue:delete(Q, IfUnused, IfEmpty) end) of
|
||||
|
|
@ -640,8 +568,7 @@ handle_method(#'queue.delete'{ticket = TicketNumber,
|
|||
message_count = PurgedMessageCount})
|
||||
end;
|
||||
|
||||
handle_method(#'queue.bind'{ticket = TicketNumber,
|
||||
queue = QueueNameBin,
|
||||
handle_method(#'queue.bind'{queue = QueueNameBin,
|
||||
exchange = ExchangeNameBin,
|
||||
routing_key = RoutingKey,
|
||||
nowait = NoWait,
|
||||
|
|
@ -652,14 +579,13 @@ handle_method(#'queue.bind'{ticket = TicketNumber,
|
|||
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
|
||||
ActualRoutingKey = expand_routing_key_shortcut(QueueNameBin, RoutingKey,
|
||||
State),
|
||||
check_ticket(TicketNumber, #ticket.active_flag, QueueName, State),
|
||||
ExchangeName = rabbit_misc:r(VHostPath, exchange, ExchangeNameBin),
|
||||
case rabbit_amqqueue:add_binding(QueueName, ExchangeName,
|
||||
ActualRoutingKey, Arguments) of
|
||||
{error, queue_not_found} ->
|
||||
{error, queue_not_found} ->
|
||||
rabbit_misc:protocol_error(
|
||||
not_found, "no ~s", [rabbit_misc:rs(QueueName)]);
|
||||
{error, exchange_not_found} ->
|
||||
{error, exchange_not_found} ->
|
||||
rabbit_misc:protocol_error(
|
||||
not_found, "no ~s", [rabbit_misc:rs(ExchangeName)]);
|
||||
{error, durability_settings_incompatible} ->
|
||||
|
|
@ -670,12 +596,10 @@ handle_method(#'queue.bind'{ticket = TicketNumber,
|
|||
return_ok(State, NoWait, #'queue.bind_ok'{})
|
||||
end;
|
||||
|
||||
handle_method(#'queue.purge'{ticket = TicketNumber,
|
||||
queue = QueueNameBin,
|
||||
handle_method(#'queue.purge'{queue = QueueNameBin,
|
||||
nowait = NoWait},
|
||||
_, State) ->
|
||||
QueueName = expand_queue_name_shortcut(QueueNameBin, State),
|
||||
check_ticket(TicketNumber, #ticket.read_flag, QueueName, State),
|
||||
{ok, PurgedMessageCount} = rabbit_amqqueue:with_or_die(
|
||||
QueueName,
|
||||
fun (Q) -> rabbit_amqqueue:purge(Q) end),
|
||||
|
|
|
|||
|
|
@ -89,17 +89,6 @@ Available commands:
|
|||
list_user_vhosts <UserName>
|
||||
list_vhost_users <VHostPath>
|
||||
|
||||
add_realm <VHostPath> <RealmName>
|
||||
delete_realm <VHostPath> <RealmName>
|
||||
list_realms <VHostPath>
|
||||
|
||||
set_permissions <UserName> <VHostPath> <RealmName> [<Permission> ...]
|
||||
Permissions management. The available permissions are 'passive',
|
||||
'active', 'write' and 'read', corresponding to the permissions
|
||||
referred to in AMQP's \"access.request\" message, or 'all' as an
|
||||
abbreviation for all defined permission flags.
|
||||
list_permissions <UserName> <VHostPath>
|
||||
|
||||
<node> should be the name of the master node of the RabbitMQ cluster. It
|
||||
defaults to the node named \"rabbit\" on the local host. On a host named
|
||||
\"server.example.com\", the master node will usually be rabbit@server (unless
|
||||
|
|
@ -187,68 +176,7 @@ action(list_user_vhosts, Node, Args = [_Username]) ->
|
|||
|
||||
action(list_vhost_users, Node, Args = [_VHostPath]) ->
|
||||
io:format("Listing users for vhosts ~p...", Args),
|
||||
display_list(call(Node, {rabbit_access_control, list_vhost_users, Args}));
|
||||
|
||||
action(add_realm, Node, [VHostPath, RealmName]) ->
|
||||
io:format("Adding realm ~p to vhost ~p ...", [RealmName, VHostPath]),
|
||||
rpc_call(Node, rabbit_realm, add_realm,
|
||||
[realm_rsrc(VHostPath, RealmName)]);
|
||||
|
||||
action(delete_realm, Node, [VHostPath, RealmName]) ->
|
||||
io:format("Deleting realm ~p from vhost ~p ...", [RealmName, VHostPath]),
|
||||
rpc_call(Node, rabbit_realm, delete_realm,
|
||||
[realm_rsrc(VHostPath, RealmName)]);
|
||||
|
||||
action(list_realms, Node, Args = [_VHostPath]) ->
|
||||
io:format("Listing realms for vhost ~p ...", Args),
|
||||
display_list(call(Node, {rabbit_realm, list_vhost_realms, Args}));
|
||||
|
||||
action(set_permissions, Node,
|
||||
[Username, VHostPath, RealmName | Permissions]) ->
|
||||
io:format("Setting permissions for user ~p, vhost ~p, realm ~p ...",
|
||||
[Username, VHostPath, RealmName]),
|
||||
CheckedPermissions = check_permissions(Permissions),
|
||||
Ticket = #ticket{
|
||||
realm_name = realm_rsrc(VHostPath, RealmName),
|
||||
passive_flag = lists:member(passive, CheckedPermissions),
|
||||
active_flag = lists:member(active, CheckedPermissions),
|
||||
write_flag = lists:member(write, CheckedPermissions),
|
||||
read_flag = lists:member(read, CheckedPermissions)},
|
||||
rpc_call(Node, rabbit_access_control, map_user_realm,
|
||||
[list_to_binary(Username), Ticket]);
|
||||
|
||||
action(list_permissions, Node, Args = [_Username, _VHostPath]) ->
|
||||
io:format("Listing permissions for user ~p in vhost ~p ...", Args),
|
||||
Perms = call(Node, {rabbit_access_control, list_user_realms, Args}),
|
||||
if is_list(Perms) ->
|
||||
lists:foreach(
|
||||
fun ({RealmName, Pattern}) ->
|
||||
io:format("~n~s: ~p",
|
||||
[binary_to_list(RealmName),
|
||||
rabbit_misc:permission_list(Pattern)])
|
||||
end,
|
||||
lists:sort(Perms)),
|
||||
io:nl(),
|
||||
ok;
|
||||
true -> Perms
|
||||
end.
|
||||
|
||||
check_permissions([]) -> [];
|
||||
check_permissions(["all" | R]) ->
|
||||
[passive, active, write, read | check_permissions(R)];
|
||||
check_permissions([P | R]) when (P == "passive") or
|
||||
(P == "active") or
|
||||
(P == "write") or
|
||||
(P == "read") ->
|
||||
[list_to_atom(P) | check_permissions(R)];
|
||||
check_permissions([P | _R]) ->
|
||||
io:format("~nError: invalid permission flag ~p~n", [P]),
|
||||
usage().
|
||||
|
||||
realm_rsrc(VHostPath, RealmName) ->
|
||||
rabbit_misc:r(list_to_binary(VHostPath),
|
||||
realm,
|
||||
list_to_binary(RealmName)).
|
||||
display_list(call(Node, {rabbit_access_control, list_vhost_users, Args})).
|
||||
|
||||
display_list(L) when is_list(L) ->
|
||||
lists:foreach(fun (I) ->
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@
|
|||
|
||||
init([DefaultVHost]) ->
|
||||
#exchange{} = rabbit_exchange:declare(
|
||||
#resource{virtual_host = DefaultVHost,
|
||||
kind = realm,
|
||||
name = <<"/admin">>},
|
||||
?LOG_EXCH_NAME,
|
||||
rabbit_misc:r(DefaultVHost, exchange, ?LOG_EXCH_NAME),
|
||||
topic, true, false, []),
|
||||
{ok, #resource{virtual_host = DefaultVHost,
|
||||
kind = exchange,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
-include("rabbit.hrl").
|
||||
-include("rabbit_framing.hrl").
|
||||
|
||||
-export([recover/0, declare/6, lookup/1, lookup_or_die/1,
|
||||
-export([recover/0, declare/5, lookup/1, lookup_or_die/1,
|
||||
list_vhost_exchanges/1, list_exchange_bindings/1,
|
||||
simple_publish/6, simple_publish/3,
|
||||
route/2]).
|
||||
|
|
@ -50,21 +50,21 @@
|
|||
not_found() | {'error', 'unroutable' | 'not_delivered'}).
|
||||
|
||||
-spec(recover/0 :: () -> 'ok').
|
||||
-spec(declare/6 :: (realm_name(), name(), exchange_type(), bool(), bool(),
|
||||
-spec(declare/5 :: (exchange_name(), exchange_type(), bool(), bool(),
|
||||
amqp_table()) -> exchange()).
|
||||
-spec(check_type/1 :: (binary()) -> atom()).
|
||||
-spec(assert_type/2 :: (exchange(), atom()) -> 'ok').
|
||||
-spec(assert_type/2 :: (exchange(), atom()) -> 'ok').
|
||||
-spec(lookup/1 :: (exchange_name()) -> {'ok', exchange()} | not_found()).
|
||||
-spec(lookup_or_die/1 :: (exchange_name()) -> exchange()).
|
||||
-spec(list_vhost_exchanges/1 :: (vhost()) -> [exchange()]).
|
||||
-spec(list_exchange_bindings/1 :: (exchange_name()) ->
|
||||
-spec(list_exchange_bindings/1 :: (exchange_name()) ->
|
||||
[{queue_name(), routing_key(), amqp_table()}]).
|
||||
-spec(simple_publish/6 ::
|
||||
(bool(), bool(), exchange_name(), routing_key(), binary(), binary()) ->
|
||||
publish_res()).
|
||||
-spec(simple_publish/3 :: (bool(), bool(), message()) -> publish_res()).
|
||||
-spec(route/2 :: (exchange(), routing_key()) -> [pid()]).
|
||||
-spec(add_binding/2 :: (binding_spec(), amqqueue()) ->
|
||||
-spec(add_binding/2 :: (binding_spec(), amqqueue()) ->
|
||||
'ok' | not_found() |
|
||||
{'error', 'durability_settings_incompatible'}).
|
||||
-spec(delete_binding/2 :: (binding_spec(), amqqueue()) ->
|
||||
|
|
@ -90,23 +90,21 @@ recover_durable_exchanges() ->
|
|||
end, ok, durable_exchanges)
|
||||
end).
|
||||
|
||||
declare(RealmName, NameBin, Type, Durable, AutoDelete, Args) ->
|
||||
XName = rabbit_misc:r(RealmName, exchange, NameBin),
|
||||
Exchange = #exchange{name = XName,
|
||||
declare(ExchangeName, Type, Durable, AutoDelete, Args) ->
|
||||
Exchange = #exchange{name = ExchangeName,
|
||||
type = Type,
|
||||
durable = Durable,
|
||||
auto_delete = AutoDelete,
|
||||
arguments = Args},
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
case mnesia:wread({exchange, XName}) of
|
||||
case mnesia:wread({exchange, ExchangeName}) of
|
||||
[] -> ok = mnesia:write(Exchange),
|
||||
if Durable ->
|
||||
ok = mnesia:write(
|
||||
durable_exchanges, Exchange, write);
|
||||
true -> ok
|
||||
end,
|
||||
ok = rabbit_realm:add(RealmName, XName),
|
||||
Exchange;
|
||||
[ExistingX] -> ExistingX
|
||||
end
|
||||
|
|
@ -147,15 +145,14 @@ list_vhost_exchanges(VHostPath) ->
|
|||
|
||||
list_exchange_bindings(Name) ->
|
||||
[{QueueName, RoutingKey, Arguments} ||
|
||||
#binding{handlers = Handlers} <- bindings_for_exchange(Name),
|
||||
#handler{binding_spec = #binding_spec{routing_key = RoutingKey,
|
||||
arguments = Arguments},
|
||||
queue = QueueName} <- Handlers].
|
||||
#binding{handlers = Handlers} <- bindings_for_exchange(Name),
|
||||
#handler{binding_spec = #binding_spec{routing_key = RoutingKey,
|
||||
arguments = Arguments},
|
||||
queue = QueueName} <- Handlers].
|
||||
|
||||
bindings_for_exchange(Name) ->
|
||||
qlc:e(qlc:q([B ||
|
||||
B = #binding{key = K} <- mnesia:table(binding),
|
||||
element(1, K) == Name])).
|
||||
qlc:e(qlc:q([B || B = #binding{key = K} <- mnesia:table(binding),
|
||||
element(1, K) == Name])).
|
||||
|
||||
empty_handlers() ->
|
||||
[].
|
||||
|
|
@ -187,7 +184,7 @@ simple_publish(Mandatory, Immediate,
|
|||
|
||||
%% return the list of qpids to which a message with a given routing
|
||||
%% key, sent to a particular exchange, should be delivered.
|
||||
%%
|
||||
%%
|
||||
%% The function ensures that a qpid appears in the return list exactly
|
||||
%% as many times as a message should be delivered to it. With the
|
||||
%% current exchange types that is at most once.
|
||||
|
|
@ -197,7 +194,7 @@ route(#exchange{name = Name, type = topic}, RoutingKey) ->
|
|||
mnesia:activity(
|
||||
async_dirty,
|
||||
fun () ->
|
||||
qlc:e(qlc:q([handler_qpids(H) ||
|
||||
qlc:e(qlc:q([handler_qpids(H) ||
|
||||
#binding{key = {Name1, PatternKey},
|
||||
handlers = H}
|
||||
<- mnesia:table(binding),
|
||||
|
|
@ -375,6 +372,5 @@ do_internal_delete(ExchangeName, Bindings) ->
|
|||
ok = mnesia:delete({binding, K})
|
||||
end, Bindings),
|
||||
ok = mnesia:delete({durable_exchanges, ExchangeName}),
|
||||
ok = mnesia:delete({exchange, ExchangeName}),
|
||||
ok = rabbit_realm:delete_from_all(ExchangeName)
|
||||
ok = mnesia:delete({exchange, ExchangeName})
|
||||
end.
|
||||
|
|
|
|||
|
|
@ -29,14 +29,12 @@
|
|||
|
||||
-export([method_record_type/1, polite_pause/0, polite_pause/1]).
|
||||
-export([die/1, frame_error/2, protocol_error/3, protocol_error/4]).
|
||||
-export([strict_ticket_checking/0]).
|
||||
-export([get_config/1, get_config/2, set_config/2]).
|
||||
-export([dirty_read/1]).
|
||||
-export([r/3, r/2, rs/1]).
|
||||
-export([permission_list/1]).
|
||||
-export([enable_cover/0, report_cover/0]).
|
||||
-export([with_exit_handler/2]).
|
||||
-export([with_user/2, with_vhost/2, with_realm/2, with_user_and_vhost/3]).
|
||||
-export([with_user/2, with_vhost/2, with_user_and_vhost/3]).
|
||||
-export([execute_mnesia_transaction/1]).
|
||||
-export([ensure_ok/2]).
|
||||
-export([localnode/1, tcp_name/3]).
|
||||
|
|
@ -64,32 +62,28 @@
|
|||
(atom() | amqp_error(), string(), [any()]) -> no_return()).
|
||||
-spec(protocol_error/4 ::
|
||||
(atom() | amqp_error(), string(), [any()], atom()) -> no_return()).
|
||||
-spec(strict_ticket_checking/0 :: () -> bool()).
|
||||
-spec(get_config/1 :: (atom()) -> {'ok', any()} | not_found()).
|
||||
-spec(get_config/2 :: (atom(), A) -> A).
|
||||
-spec(set_config/2 :: (atom(), any()) -> 'ok').
|
||||
-spec(dirty_read/1 :: ({atom(), any()}) -> {'ok', any()} | not_found()).
|
||||
-spec(r/3 :: (realm_name() | vhost(), K, name()) ->
|
||||
r(K) when is_subtype(K, atom())).
|
||||
-spec(r/3 :: (vhost(), K, name()) -> r(K) when is_subtype(K, atom())).
|
||||
-spec(r/2 :: (vhost(), K) -> #resource{virtual_host :: vhost(),
|
||||
kind :: K,
|
||||
name :: '_'}
|
||||
when is_subtype(K, atom())).
|
||||
-spec(rs/1 :: (r(atom())) -> string()).
|
||||
-spec(permission_list/1 :: (ticket()) -> [permission()]).
|
||||
-spec(rs/1 :: (r(atom())) -> string()).
|
||||
-spec(enable_cover/0 :: () -> 'ok' | {'error', any()}).
|
||||
-spec(report_cover/0 :: () -> 'ok').
|
||||
-spec(with_exit_handler/2 :: (thunk(A), thunk(A)) -> A).
|
||||
-spec(with_user/2 :: (username(), thunk(A)) -> A).
|
||||
-spec(with_exit_handler/2 :: (thunk(A), thunk(A)) -> A).
|
||||
-spec(with_user/2 :: (username(), thunk(A)) -> A).
|
||||
-spec(with_vhost/2 :: (vhost(), thunk(A)) -> A).
|
||||
-spec(with_realm/2 :: (realm_name(), thunk(A)) -> A).
|
||||
-spec(with_user_and_vhost/3 :: (username(), vhost(), thunk(A)) -> A).
|
||||
-spec(with_user_and_vhost/3 :: (username(), vhost(), thunk(A)) -> A).
|
||||
-spec(execute_mnesia_transaction/1 :: (thunk(A)) -> A).
|
||||
-spec(ensure_ok/2 :: ('ok' | {'error', any()}, atom()) -> 'ok').
|
||||
-spec(ensure_ok/2 :: ('ok' | {'error', any()}, atom()) -> 'ok').
|
||||
-spec(localnode/1 :: (atom()) -> node()).
|
||||
-spec(tcp_name/3 :: (atom(), ip_address(), ip_port()) -> atom()).
|
||||
-spec(tcp_name/3 :: (atom(), ip_address(), ip_port()) -> atom()).
|
||||
-spec(intersperse/2 :: (A, [A]) -> [A]).
|
||||
-spec(upmap/2 :: (fun ((A) -> B), [A]) -> [B]).
|
||||
-spec(upmap/2 :: (fun ((A) -> B), [A]) -> [B]).
|
||||
-spec(map_in_order/2 :: (fun ((A) -> B), [A]) -> [B]).
|
||||
-spec(guid/0 :: () -> guid()).
|
||||
-spec(string_guid/1 :: (any()) -> string()).
|
||||
|
|
@ -128,24 +122,6 @@ protocol_error(Error, Explanation, Params, Method) ->
|
|||
CompleteExplanation = lists:flatten(io_lib:format(Explanation, Params)),
|
||||
exit({amqp, Error, CompleteExplanation, Method}).
|
||||
|
||||
boolean_config_param(Name, TrueValue, FalseValue, DefaultValue) ->
|
||||
ActualValue = get_config(Name, DefaultValue),
|
||||
if
|
||||
ActualValue == TrueValue ->
|
||||
true;
|
||||
ActualValue == FalseValue ->
|
||||
false;
|
||||
true ->
|
||||
rabbit_log:error(
|
||||
"Bad setting for config param '~w': ~p~n" ++
|
||||
"legal values are '~w', '~w'; using default value '~w'",
|
||||
[Name, ActualValue, TrueValue, FalseValue, DefaultValue]),
|
||||
DefaultValue == TrueValue
|
||||
end.
|
||||
|
||||
strict_ticket_checking() ->
|
||||
boolean_config_param(strict_ticket_checking, enabled, disabled, disabled).
|
||||
|
||||
get_config(Key) ->
|
||||
case dirty_read({rabbit_config, Key}) of
|
||||
{ok, {rabbit_config, Key, V}} -> {ok, V};
|
||||
|
|
@ -180,19 +156,6 @@ rs(#resource{virtual_host = VHostPath, kind = Kind, name = Name}) ->
|
|||
lists:flatten(io_lib:format("~s '~s' in vhost '~s'",
|
||||
[Kind, Name, VHostPath])).
|
||||
|
||||
permission_list(Ticket = #ticket{}) ->
|
||||
lists:foldr(fun ({Field, Label}, L) ->
|
||||
case element(Field, Ticket) of
|
||||
true -> [Label | L];
|
||||
false -> L
|
||||
end
|
||||
end,
|
||||
[],
|
||||
[{#ticket.passive_flag, passive},
|
||||
{#ticket.active_flag, active},
|
||||
{#ticket.write_flag, write},
|
||||
{#ticket.read_flag, read}]).
|
||||
|
||||
enable_cover() ->
|
||||
case cover:compile_beam_directory("ebin") of
|
||||
{error,Reason} -> {error,Reason};
|
||||
|
|
@ -251,32 +214,13 @@ with_user(Username, Thunk) ->
|
|||
with_vhost(VHostPath, Thunk) ->
|
||||
fun () ->
|
||||
case mnesia:read({vhost, VHostPath}) of
|
||||
[] ->
|
||||
[] ->
|
||||
mnesia:abort({no_such_vhost, VHostPath});
|
||||
[_V] ->
|
||||
Thunk()
|
||||
end
|
||||
end.
|
||||
|
||||
with_realm(Name = #resource{virtual_host = VHostPath, kind = realm},
|
||||
Thunk) ->
|
||||
fun () ->
|
||||
case mnesia:read({realm, Name}) of
|
||||
[] ->
|
||||
mnesia:abort({no_such_realm, Name});
|
||||
[_R] ->
|
||||
case mnesia:match_object(
|
||||
#vhost_realm{virtual_host = VHostPath,
|
||||
realm = Name}) of
|
||||
[] ->
|
||||
%% This should never happen
|
||||
mnesia:abort({no_such_realm, Name});
|
||||
[_VR] ->
|
||||
Thunk()
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
with_user_and_vhost(Username, VHostPath, Thunk) ->
|
||||
with_user(Username, with_vhost(VHostPath, Thunk)).
|
||||
|
||||
|
|
|
|||
|
|
@ -102,29 +102,6 @@ table_definitions() ->
|
|||
{index, [virtual_host]}]},
|
||||
{vhost, [{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, vhost)}]},
|
||||
{vhost_realm, [{type, bag},
|
||||
{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, vhost_realm)},
|
||||
{index, [realm]}]},
|
||||
{realm, [{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, realm)}]},
|
||||
{realm_exchange, [{disc_copies, [node()]},
|
||||
{record_name, realm_resource},
|
||||
{attributes, record_info(fields, realm_resource)}]},
|
||||
{realm_queue, [{disc_copies, [node()]},
|
||||
{record_name, realm_resource},
|
||||
{attributes, record_info(fields, realm_resource)}]},
|
||||
{user_realm, [{type, bag},
|
||||
{disc_copies, [node()]},
|
||||
{attributes, record_info(fields, user_realm)},
|
||||
{index, [realm]}]},
|
||||
{exclusive_realm_visitor,
|
||||
[{record_name, realm_visitor},
|
||||
{attributes, record_info(fields, realm_visitor)},
|
||||
{index, [pid]}]},
|
||||
{realm_visitor, [{type, bag},
|
||||
{attributes, record_info(fields, realm_visitor)},
|
||||
{index, [pid]}]},
|
||||
{rabbit_config, [{disc_copies, [node()]}]},
|
||||
{listener, [{type, bag},
|
||||
{attributes, record_info(fields, listener)}]},
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ handle_info({nodedown, Node}, State) ->
|
|||
%% lots of nodes. We really only need to execute this code on
|
||||
%% *one* node, rather than all of them.
|
||||
ok = rabbit_networking:on_node_down(Node),
|
||||
ok = rabbit_realm:on_node_down(Node),
|
||||
ok = rabbit_amqqueue:on_node_down(Node),
|
||||
{noreply, State};
|
||||
handle_info(_Info, State) ->
|
||||
|
|
|
|||
|
|
@ -1,302 +0,0 @@
|
|||
%% The contents of this file are subject to the Mozilla Public License
|
||||
%% Version 1.1 (the "License"); you may not use this file except in
|
||||
%% compliance with the License. You may obtain a copy of the License at
|
||||
%% http://www.mozilla.org/MPL/
|
||||
%%
|
||||
%% Software distributed under the License is distributed on an "AS IS"
|
||||
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
%% License for the specific language governing rights and limitations
|
||||
%% under the License.
|
||||
%%
|
||||
%% The Original Code is RabbitMQ.
|
||||
%%
|
||||
%% The Initial Developers of the Original Code are LShift Ltd.,
|
||||
%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
|
||||
%%
|
||||
%% Portions created by LShift Ltd., Cohesive Financial Technologies
|
||||
%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008
|
||||
%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
|
||||
%% Technologies Ltd.;
|
||||
%%
|
||||
%% All Rights Reserved.
|
||||
%%
|
||||
%% Contributor(s): ______________________________________.
|
||||
%%
|
||||
|
||||
-module(rabbit_realm).
|
||||
|
||||
-export([recover/0]).
|
||||
-export([add_realm/1, delete_realm/1, list_vhost_realms/1]).
|
||||
-export([add/2, delete/2, check/2, delete_from_all/1]).
|
||||
-export([access_request/3, enter_realm/3, leave_realms/1]).
|
||||
-export([on_node_down/1]).
|
||||
|
||||
-include("rabbit.hrl").
|
||||
-include_lib("stdlib/include/qlc.hrl").
|
||||
|
||||
%%----------------------------------------------------------------------------
|
||||
|
||||
-ifdef(use_specs).
|
||||
|
||||
-type(e_or_q() :: 'exchange' | 'queue').
|
||||
|
||||
-spec(recover/0 :: () -> 'ok').
|
||||
-spec(add_realm/1 :: (realm_name()) -> 'ok').
|
||||
-spec(delete_realm/1 :: (realm_name()) -> 'ok').
|
||||
-spec(list_vhost_realms/1 :: (vhost()) -> [name()]).
|
||||
-spec(add/2 :: (realm_name(), r(e_or_q())) -> 'ok').
|
||||
-spec(delete/2 :: (realm_name(), r(e_or_q())) -> 'ok').
|
||||
-spec(check/2 :: (realm_name(), r(e_or_q())) -> bool() | not_found()).
|
||||
-spec(delete_from_all/1 :: (r(e_or_q())) -> 'ok').
|
||||
-spec(access_request/3 :: (username(), bool(), ticket()) ->
|
||||
'ok' | not_found() | {'error', 'bad_realm_path' |
|
||||
'access_refused' |
|
||||
'resource_locked'}).
|
||||
-spec(enter_realm/3 :: (realm_name(), bool(), pid()) ->
|
||||
'ok' | {'error', 'resource_locked'}).
|
||||
-spec(leave_realms/1 :: (pid()) -> 'ok').
|
||||
-spec(on_node_down/1 :: (node()) -> 'ok').
|
||||
|
||||
-endif.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
recover() ->
|
||||
%% preens resource lists, limiting them to currently-extant resources
|
||||
rabbit_misc:execute_mnesia_transaction(fun preen_realms/0).
|
||||
|
||||
add_realm(Name = #resource{virtual_host = VHostPath, kind = realm}) ->
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
rabbit_misc:with_vhost(
|
||||
VHostPath,
|
||||
fun () ->
|
||||
case mnesia:read({realm, Name}) of
|
||||
[] ->
|
||||
NewRealm = #realm{name = Name},
|
||||
ok = mnesia:write(NewRealm),
|
||||
ok = mnesia:write(
|
||||
#vhost_realm{virtual_host = VHostPath,
|
||||
realm = Name}),
|
||||
ok;
|
||||
[_R] ->
|
||||
mnesia:abort({realm_already_exists, Name})
|
||||
end
|
||||
end)).
|
||||
|
||||
delete_realm(Name = #resource{virtual_host = VHostPath, kind = realm}) ->
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
rabbit_misc:with_vhost(
|
||||
VHostPath,
|
||||
rabbit_misc:with_realm(
|
||||
Name,
|
||||
fun () ->
|
||||
ok = mnesia:delete({realm, Name}),
|
||||
ok = mnesia:delete_object(
|
||||
#vhost_realm{virtual_host = VHostPath,
|
||||
realm = Name}),
|
||||
lists:foreach(fun mnesia:delete_object/1,
|
||||
mnesia:index_read(user_realm, Name,
|
||||
#user_realm.realm)),
|
||||
ok
|
||||
end))).
|
||||
|
||||
list_vhost_realms(VHostPath) ->
|
||||
[Name ||
|
||||
#vhost_realm{realm = #resource{name = Name}} <-
|
||||
%% TODO: use dirty ops instead
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
rabbit_misc:with_vhost(
|
||||
VHostPath,
|
||||
fun () -> mnesia:read({vhost_realm, VHostPath}) end))].
|
||||
|
||||
add(Realm = #resource{kind = realm}, Resource = #resource{}) ->
|
||||
manage_link(fun mnesia:write/3, Realm, Resource).
|
||||
|
||||
delete(Realm = #resource{kind = realm}, Resource = #resource{}) ->
|
||||
manage_link(fun mnesia:delete_object/3, Realm, Resource).
|
||||
|
||||
% This links or unlinks a resource to a realm
|
||||
manage_link(Action, Realm = #resource{kind = realm, name = RealmName},
|
||||
R = #resource{name = Name}) ->
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
case mnesia:read({realm, Realm}) of
|
||||
[] -> mnesia:abort(not_found);
|
||||
[_] -> Action(realm_table_for_resource(R),
|
||||
#realm_resource{realm = RealmName,
|
||||
resource = Name},
|
||||
write)
|
||||
end
|
||||
end).
|
||||
|
||||
realm_table_for_resource(#resource{kind = exchange}) -> realm_exchange;
|
||||
realm_table_for_resource(#resource{kind = queue}) -> realm_queue.
|
||||
parent_table_for_resource(#resource{kind = exchange}) -> exchange;
|
||||
parent_table_for_resource(#resource{kind = queue}) -> amqqueue.
|
||||
|
||||
|
||||
check(#resource{kind = realm, name = Realm}, R = #resource{name = Name}) ->
|
||||
case mnesia:dirty_match_object(realm_table_for_resource(R),
|
||||
#realm_resource{realm = Realm,
|
||||
resource = Name}) of
|
||||
[] -> false;
|
||||
_ -> true
|
||||
end.
|
||||
|
||||
% Requires a mnesia transaction.
|
||||
delete_from_all(R = #resource{name = Name}) ->
|
||||
mnesia:delete_object(realm_table_for_resource(R),
|
||||
#realm_resource{realm = '_', resource = Name},
|
||||
write).
|
||||
|
||||
access_request(Username, Exclusive, Ticket = #ticket{realm_name = RealmName})
|
||||
when is_binary(Username) ->
|
||||
%% FIXME: We should do this all in a single tx. Otherwise we may
|
||||
%% a) get weird answers, b) create inconsistencies in the db
|
||||
%% (e.g. realm_visitor records referring to non-existing realms).
|
||||
case check_and_lookup(RealmName) of
|
||||
{error, Reason} ->
|
||||
{error, Reason};
|
||||
{ok, _Realm} ->
|
||||
{ok, U} = rabbit_access_control:lookup_user(Username),
|
||||
case rabbit_access_control:lookup_realm_access(U, RealmName) of
|
||||
none ->
|
||||
{error, access_refused};
|
||||
TicketPattern ->
|
||||
case match_ticket(TicketPattern, Ticket) of
|
||||
no_match ->
|
||||
{error, access_refused};
|
||||
match ->
|
||||
enter_realm(RealmName, Exclusive, self())
|
||||
end
|
||||
end
|
||||
end.
|
||||
|
||||
enter_realm(Name = #resource{kind = realm}, IsExclusive, Pid) ->
|
||||
RealmVisitor = #realm_visitor{realm = Name, pid = Pid},
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
case mnesia:read({exclusive_realm_visitor, Name}) of
|
||||
[] when IsExclusive ->
|
||||
ok = mnesia:delete_object(RealmVisitor),
|
||||
%% TODO: find a more efficient way of checking
|
||||
%% for "no machting results" that doesn't
|
||||
%% involve retrieving all the records
|
||||
case mnesia:read({realm_visitor, Name}) of
|
||||
[] ->
|
||||
mnesia:write(
|
||||
exclusive_realm_visitor, RealmVisitor, write),
|
||||
ok;
|
||||
[_|_] ->
|
||||
{error, resource_locked}
|
||||
end;
|
||||
[] ->
|
||||
ok = mnesia:write(RealmVisitor),
|
||||
ok;
|
||||
[RealmVisitor] when IsExclusive -> ok;
|
||||
[RealmVisitor] ->
|
||||
ok = mnesia:delete({exclusive_realm_visitor, Name}),
|
||||
ok = mnesia:write(RealmVisitor),
|
||||
ok;
|
||||
[_] ->
|
||||
{error, resource_locked}
|
||||
end
|
||||
end).
|
||||
|
||||
leave_realms(Pid) ->
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
case mnesia:index_read(exclusive_realm_visitor, Pid,
|
||||
#realm_visitor.pid) of
|
||||
[] -> ok;
|
||||
[R] ->
|
||||
ok = mnesia:delete_object(
|
||||
exclusive_realm_visitor, R, write)
|
||||
end,
|
||||
lists:foreach(fun mnesia:delete_object/1,
|
||||
mnesia:index_read(realm_visitor, Pid,
|
||||
#realm_visitor.pid)),
|
||||
ok
|
||||
end).
|
||||
|
||||
on_node_down(Node) ->
|
||||
rabbit_misc:execute_mnesia_transaction(
|
||||
fun () ->
|
||||
lists:foreach(
|
||||
fun (T) -> ok = remove_visitors(Node, T) end,
|
||||
[exclusive_realm_visitor, realm_visitor]),
|
||||
ok
|
||||
end).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%% This iterates through the realm_exchange and realm_queue link tables
|
||||
%% and deletes rows that have no underlying exchange or queue record.
|
||||
preen_realms() ->
|
||||
lists:foreach(fun preen_realm/1, [exchange, queue]),
|
||||
ok.
|
||||
|
||||
preen_realm(Kind) ->
|
||||
R = #resource{kind = Kind},
|
||||
Table = realm_table_for_resource(R),
|
||||
Cursor = qlc:cursor(
|
||||
qlc:q([L#realm_resource.resource ||
|
||||
L <- mnesia:table(Table)])),
|
||||
preen_next(Cursor, Table, parent_table_for_resource(R)),
|
||||
qlc:delete_cursor(Cursor).
|
||||
|
||||
preen_next(Cursor, Table, ParentTable) ->
|
||||
case qlc:next_answers(Cursor, 1) of
|
||||
[] -> ok;
|
||||
[Name] ->
|
||||
case mnesia:read({ParentTable, Name}) of
|
||||
[] -> mnesia:delete_object(
|
||||
Table,
|
||||
#realm_resource{realm = '_', resource = Name},
|
||||
write);
|
||||
_ -> ok
|
||||
end,
|
||||
preen_next(Cursor, Table, ParentTable)
|
||||
end.
|
||||
|
||||
check_and_lookup(RealmName = #resource{kind = realm,
|
||||
name = <<"/data", _/binary>>}) ->
|
||||
lookup(RealmName);
|
||||
check_and_lookup(RealmName = #resource{kind = realm,
|
||||
name = <<"/admin", _/binary>>}) ->
|
||||
lookup(RealmName);
|
||||
check_and_lookup(_) ->
|
||||
{error, bad_realm_path}.
|
||||
|
||||
lookup(Name = #resource{kind = realm}) ->
|
||||
rabbit_misc:dirty_read({realm, Name}).
|
||||
|
||||
match_ticket(#ticket{passive_flag = PP,
|
||||
active_flag = PA,
|
||||
write_flag = PW,
|
||||
read_flag = PR},
|
||||
#ticket{passive_flag = TP,
|
||||
active_flag = TA,
|
||||
write_flag = TW,
|
||||
read_flag = TR}) ->
|
||||
if
|
||||
%% Matches if either we're not requesting passive access, or
|
||||
%% passive access is permitted, and ...
|
||||
(not(TP) orelse PP) andalso
|
||||
(not(TA) orelse PA) andalso
|
||||
(not(TW) orelse PW) andalso
|
||||
(not(TR) orelse PR) ->
|
||||
match;
|
||||
true ->
|
||||
no_match
|
||||
end.
|
||||
|
||||
remove_visitors(Node, T) ->
|
||||
qlc:fold(
|
||||
fun (R, Acc) ->
|
||||
ok = mnesia:delete_object(T, R, write),
|
||||
Acc
|
||||
end,
|
||||
ok,
|
||||
qlc:q([R || R = #realm_visitor{pid = Pid} <- mnesia:table(T),
|
||||
node(Pid) == Node])).
|
||||
|
|
@ -284,31 +284,12 @@ test_user_management() ->
|
|||
control_action(unmap_user_vhost, ["foo", "/"]),
|
||||
{error, {no_such_user, _}} =
|
||||
control_action(list_user_vhosts, ["foo"]),
|
||||
{error, {no_such_user, _}} =
|
||||
control_action(set_permissions, ["foo", "/", "/data"]),
|
||||
{error, {no_such_user, _}} =
|
||||
control_action(list_permissions, ["foo", "/"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(map_user_vhost, ["guest", "/testhost"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(unmap_user_vhost, ["guest", "/testhost"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(list_vhost_users, ["/testhost"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(set_permissions, ["guest", "/testhost", "/data"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(list_permissions, ["guest", "/testhost"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(add_realm, ["/testhost", "/data/test"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(delete_realm, ["/testhost", "/data/test"]),
|
||||
{error, {no_such_vhost, _}} =
|
||||
control_action(list_realms, ["/testhost"]),
|
||||
{error, {no_such_realm, _}} =
|
||||
control_action(set_permissions, ["guest", "/", "/data/test"]),
|
||||
{error, {no_such_realm, _}} =
|
||||
control_action(delete_realm, ["/", "/data/test"]),
|
||||
|
||||
%% user creation
|
||||
ok = control_action(add_user, ["foo", "bar"]),
|
||||
{error, {user_already_exists, _}} =
|
||||
|
|
@ -327,32 +308,6 @@ test_user_management() ->
|
|||
ok = control_action(map_user_vhost, ["foo", "/testhost"]),
|
||||
ok = control_action(list_user_vhosts, ["foo"]),
|
||||
|
||||
%% realm creation
|
||||
ok = control_action(add_realm, ["/testhost", "/data/test"]),
|
||||
{error, {realm_already_exists, _}} =
|
||||
control_action(add_realm, ["/testhost", "/data/test"]),
|
||||
ok = control_action(list_realms, ["/testhost"]),
|
||||
|
||||
%% user permissions
|
||||
ok = control_action(set_permissions,
|
||||
["foo", "/testhost", "/data/test",
|
||||
"passive", "active", "write", "read"]),
|
||||
ok = control_action(list_permissions, ["foo", "/testhost"]),
|
||||
ok = control_action(set_permissions,
|
||||
["foo", "/testhost", "/data/test", "all"]),
|
||||
ok = control_action(set_permissions,
|
||||
["foo", "/testhost", "/data/test"]),
|
||||
{error, not_mapped_to_vhost} =
|
||||
control_action(set_permissions,
|
||||
["guest", "/testhost", "/data/test"]),
|
||||
{error, not_mapped_to_vhost} =
|
||||
control_action(list_permissions, ["guest", "/testhost"]),
|
||||
|
||||
%% realm deletion
|
||||
ok = control_action(delete_realm, ["/testhost", "/data/test"]),
|
||||
{error, {no_such_realm, _}} =
|
||||
control_action(delete_realm, ["/testhost", "/data/test"]),
|
||||
|
||||
%% user/vhost unmapping
|
||||
ok = control_action(unmap_user_vhost, ["foo", "/testhost"]),
|
||||
ok = control_action(unmap_user_vhost, ["foo", "/testhost"]),
|
||||
|
|
@ -364,13 +319,7 @@ test_user_management() ->
|
|||
|
||||
%% deleting a populated vhost
|
||||
ok = control_action(add_vhost, ["/testhost"]),
|
||||
ok = control_action(add_realm, ["/testhost", "/data/test"]),
|
||||
ok = control_action(map_user_vhost, ["foo", "/testhost"]),
|
||||
ok = control_action(set_permissions,
|
||||
["foo", "/testhost", "/data/test", "all"]),
|
||||
_ = rabbit_amqqueue:declare(
|
||||
rabbit_misc:r(<<"/testhost">>, realm, <<"/data/test">>),
|
||||
<<"bar">>, true, false, []),
|
||||
ok = control_action(delete_vhost, ["/testhost"]),
|
||||
|
||||
%% user deletion
|
||||
|
|
|
|||
|
|
@ -1,131 +0,0 @@
|
|||
%% The contents of this file are subject to the Mozilla Public License
|
||||
%% Version 1.1 (the "License"); you may not use this file except in
|
||||
%% compliance with the License. You may obtain a copy of the License at
|
||||
%% http://www.mozilla.org/MPL/
|
||||
%%
|
||||
%% Software distributed under the License is distributed on an "AS IS"
|
||||
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
||||
%% License for the specific language governing rights and limitations
|
||||
%% under the License.
|
||||
%%
|
||||
%% The Original Code is RabbitMQ.
|
||||
%%
|
||||
%% The Initial Developers of the Original Code are LShift Ltd.,
|
||||
%% Cohesive Financial Technologies LLC., and Rabbit Technologies Ltd.
|
||||
%%
|
||||
%% Portions created by LShift Ltd., Cohesive Financial Technologies
|
||||
%% LLC., and Rabbit Technologies Ltd. are Copyright (C) 2007-2008
|
||||
%% LShift Ltd., Cohesive Financial Technologies LLC., and Rabbit
|
||||
%% Technologies Ltd.;
|
||||
%%
|
||||
%% All Rights Reserved.
|
||||
%%
|
||||
%% Contributor(s): ______________________________________.
|
||||
%%
|
||||
|
||||
-module(rabbit_ticket).
|
||||
-include("rabbit.hrl").
|
||||
|
||||
-export([record_ticket/2, lookup_ticket/4, check_ticket/4]).
|
||||
|
||||
-import(application).
|
||||
|
||||
%%----------------------------------------------------------------------------
|
||||
|
||||
-ifdef(use_specs).
|
||||
|
||||
-type(ticket_number() :: non_neg_integer()).
|
||||
%% we'd like to write #ticket.passive_flag | #ticket.active_flag | ...
|
||||
%% but dialyzer doesn't support that.
|
||||
-type(ticket_field() :: 3..6).
|
||||
|
||||
-spec(record_ticket/2 :: (ticket_number(), ticket()) -> 'ok').
|
||||
-spec(lookup_ticket/4 ::
|
||||
(ticket_number(), ticket_field(), username(), vhost()) ->
|
||||
ticket()).
|
||||
-spec(check_ticket/4 ::
|
||||
(ticket_number(), ticket_field(), r('exchange' | 'queue'), username()) ->
|
||||
'ok').
|
||||
|
||||
-endif.
|
||||
|
||||
%%----------------------------------------------------------------------------
|
||||
|
||||
record_ticket(TicketNumber, Ticket) ->
|
||||
put({ticket, TicketNumber}, Ticket),
|
||||
ok.
|
||||
|
||||
lookup_ticket(TicketNumber, FieldIndex, Username, VHostPath) ->
|
||||
case get({ticket, TicketNumber}) of
|
||||
undefined ->
|
||||
%% Spec: "The server MUST isolate access tickets per
|
||||
%% channel and treat an attempt by a client to mix these
|
||||
%% as a connection exception."
|
||||
rabbit_log:warning("Attempt by client to use invalid ticket ~p~n", [TicketNumber]),
|
||||
maybe_relax_checks(TicketNumber, Username, VHostPath);
|
||||
Ticket = #ticket{} ->
|
||||
case element(FieldIndex, Ticket) of
|
||||
false -> rabbit_misc:protocol_error(
|
||||
access_refused,
|
||||
"ticket ~w has insufficient permissions",
|
||||
[TicketNumber]);
|
||||
true -> Ticket
|
||||
end
|
||||
end.
|
||||
|
||||
maybe_relax_checks(TicketNumber, Username, VHostPath) ->
|
||||
case rabbit_misc:strict_ticket_checking() of
|
||||
true ->
|
||||
rabbit_misc:protocol_error(
|
||||
access_refused, "invalid ticket ~w", [TicketNumber]);
|
||||
false ->
|
||||
rabbit_log:warning("Lax ticket check mode: fabricating full ticket ~p for user ~p, vhost ~p~n",
|
||||
[TicketNumber, Username, VHostPath]),
|
||||
Ticket = rabbit_access_control:full_ticket(
|
||||
rabbit_misc:r(VHostPath, realm, <<"/data">>)),
|
||||
case rabbit_realm:access_request(Username, false, Ticket) of
|
||||
ok -> record_ticket(TicketNumber, Ticket),
|
||||
Ticket;
|
||||
{error, Reason} ->
|
||||
rabbit_misc:protocol_error(
|
||||
Reason,
|
||||
"fabrication of ticket ~w for user '~s' in vhost '~s' failed",
|
||||
[TicketNumber, Username, VHostPath])
|
||||
end
|
||||
end.
|
||||
|
||||
check_ticket(TicketNumber, FieldIndex,
|
||||
Name = #resource{virtual_host = VHostPath}, Username) ->
|
||||
#ticket{realm_name = RealmName} =
|
||||
lookup_ticket(TicketNumber, FieldIndex, Username, VHostPath),
|
||||
case resource_in_realm(RealmName, Name) of
|
||||
false ->
|
||||
case rabbit_misc:strict_ticket_checking() of
|
||||
true ->
|
||||
rabbit_misc:protocol_error(
|
||||
access_refused,
|
||||
"insufficient permissions in ticket ~w to access ~s in ~s",
|
||||
[TicketNumber, rabbit_misc:rs(Name),
|
||||
rabbit_misc:rs(RealmName)]);
|
||||
false ->
|
||||
rabbit_log:warning("Lax ticket check mode: ignoring cross-realm access for ticket ~p~n", [TicketNumber]),
|
||||
ok
|
||||
end;
|
||||
true ->
|
||||
ok
|
||||
end.
|
||||
|
||||
resource_in_realm(RealmName, ResourceName = #resource{kind = Kind}) ->
|
||||
CacheKey = {resource_cache, RealmName, Kind},
|
||||
case get(CacheKey) of
|
||||
Name when Name == ResourceName ->
|
||||
true;
|
||||
_ ->
|
||||
case rabbit_realm:check(RealmName, ResourceName) of
|
||||
true ->
|
||||
put(CacheKey, ResourceName),
|
||||
true;
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
Loading…
Reference in New Issue