diff options
author | Matthias Radestock <matthias@lshift.net> | 2008-08-14 18:46:06 +0100 |
---|---|---|
committer | Matthias Radestock <matthias@lshift.net> | 2008-08-14 18:46:06 +0100 |
commit | 24b5987e6fc6088d8ccb399857f70a0cf0fee025 (patch) | |
tree | 9434fbd63b483e455e38d7ee166407657d04c34d | |
parent | 6599426640e8863f65684f557e17f207be8e6038 (diff) | |
parent | 5f0c51fb3c34933b2f04a03ce24e05bb9e3ce943 (diff) | |
download | rabbitmq-server-24b5987e6fc6088d8ccb399857f70a0cf0fee025.tar.gz |
merge bug19089 into default
28 files changed, 407 insertions, 999 deletions
@@ -1,4 +1,4 @@ -Please see http://www.rabbitmq.com/build.html for build +Please see http://www.rabbitmq.com/build-server.html for build instructions. For your convenience, a text copy of these instructions is available @@ -5,7 +5,6 @@ EBIN_DIR=ebin INCLUDE_DIR=include SOURCES=$(wildcard $(SOURCE_DIR)/*.erl) TARGETS=$(EBIN_DIR)/rabbit_framing.beam $(patsubst $(SOURCE_DIR)/%.erl, $(EBIN_DIR)/%.beam,$(SOURCES)) -PLT=rabbit.plt WEB_URL=http://stage.rabbitmq.com/ ifndef USE_SPECS @@ -47,16 +46,13 @@ $(INCLUDE_DIR)/rabbit_framing.hrl $(SOURCE_DIR)/rabbit_framing.erl: codegen.py $ $(EBIN_DIR)/rabbit.boot $(EBIN_DIR)/rabbit.script: $(EBIN_DIR)/rabbit.app $(EBIN_DIR)/rabbit.rel $(TARGETS) erl -noshell -eval 'systools:make_script("ebin/rabbit", [{path, ["ebin"]}]), halt().' -$(PLT): $(TARGETS) - dialyzer -c $? --output_plt $@ $(shell if [ -f $@ ] ; then echo "--plt $@"; fi) - -dialyze: $(PLT) +dialyze: $(TARGETS) + dialyzer -c $? clean: cleandb rm -f $(EBIN_DIR)/*.beam rm -f $(EBIN_DIR)/rabbit.boot $(EBIN_DIR)/rabbit.script rm -f $(INCLUDE_DIR)/rabbit_framing.hrl $(SOURCE_DIR)/rabbit_framing.erl codegen.pyc - rm -f $(PLT) cleandb: stop-node erl -mnesia dir '"$(MNESIA_DIR)"' -noshell -eval 'lists:foreach(fun file:delete/1, filelib:wildcard(mnesia:system_info(directory) ++ "/*")), halt().' @@ -106,7 +102,7 @@ generic_stage: elinks -dump -no-references -no-numbering $(WEB_URL)install.html \ >> $(GENERIC_STAGE_DIR)/INSTALL; \ cp BUILD.in $(GENERIC_STAGE_DIR)/BUILD; \ - elinks -dump -no-references -no-numbering $(WEB_URL)build.html \ + elinks -dump -no-references -no-numbering $(WEB_URL)build-server.html \ >> $(GENERIC_STAGE_DIR)/BUILD; \ else \ cp INSTALL $(GENERIC_STAGE_DIR); \ @@ -123,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)) @@ -137,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 diff --git a/docs/rabbitmq-multi.pod b/docs/rabbitmq-multi.pod new file mode 100644 index 00000000..2e3f28c8 --- /dev/null +++ b/docs/rabbitmq-multi.pod @@ -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 diff --git a/docs/rabbitmq-server.pod b/docs/rabbitmq-server.pod new file mode 100644 index 00000000..1eaf2dfd --- /dev/null +++ b/docs/rabbitmq-server.pod @@ -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 diff --git a/docs/rabbitmqctl.pod b/docs/rabbitmqctl.pod new file mode 100644 index 00000000..db31b621 --- /dev/null +++ b/docs/rabbitmqctl.pod @@ -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 diff --git a/ebin/rabbit.app b/ebin/rabbit.app index 20d5afcf..0326f461 100644 --- a/ebin/rabbit.app +++ b/ebin/rabbit.app @@ -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, diff --git a/include/rabbit.hrl b/include/rabbit.hrl index 21900294..cc8fb1b5 100644 --- a/include/rabbit.hrl +++ b/include/rabbit.hrl @@ -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(), diff --git a/packaging/RPMS/Fedora/README.txt b/packaging/RPMS/Fedora/README.txt index a7db530b..6f313259 100644 --- a/packaging/RPMS/Fedora/README.txt +++ b/packaging/RPMS/Fedora/README.txt @@ -1,8 +1,7 @@ Notes on creating rpms for rabbitmq -Assuming that rpm will be built under $TOP_DIR/rpm -directory the rpm macros configuration file -would look like: +Assuming that rpm will be built under $TOP_DIR/rpm, +the main configuration variables would look like: %_topdir $TOP_DIR/rpm %_tmppath $TOP_DIR/rpm/tmp @@ -11,11 +10,7 @@ would look like: %_includedir /usr/include %_mandir /usr/share/man -Where $TOP_DIR can be any directory (usually $HOME) -However this configuration has to be under the following -path: -$HOME/.rpmmacros -since this is a fixed place where rpmbuild looks for macros. +Where $TOP_DIR can be any directory (default is $HOME). The $TOP_DIR/rpm directory has following structure: @@ -24,14 +19,14 @@ rpm +---- SOURCES // where source tarballs are put +---- SPECS // directory containing specs +---- SRPMS // rpmbuild puts here srpms - +---- RPMS // rpmbuils puts here rpms - +---- tmp // where rpm packages are built + +---- RPMS // rpmbuils puts here rpms + +---- tmp // where rpm packages are built Makefile will copy the source tarball from fixed directory specified by $TARBALL_DIR to SOURCES directory and similarly specs from $SPEC_DIR to SPECS directory. -'make rpms' should create both client and server rabbitmq. +'make rpms' should create rabbitmq-server package. If there are any errors reported by rpmbuild this is possibly due to incorrect name of the packages (if all dependencies are satisifed) - different distros @@ -39,15 +34,16 @@ can have slightly different names. rpms and srpms are placed in their respective directories. -'make prepare' will create the necessary structure and -create the rpmmacros file. Change top variables to adjust -it to your system. Note that it will *overwrite* any current -rpmmacros configuration file. +'make prepare' will create the necessary structure. +Change main configuration variables specified in the 'DEFINES' +variable in the Makefile to adjust it to your system. +Note that it will *overwrite* any current rpmmacros +configurations. The first thing to do for building rpms is to create you own source tarball of AMQ. In the spec files two top variables determine the name of the tarball. Adjust it to you needs. -The final name has to match the *Source* tag in specs' headers. +The final name has to match the *Source* tag in spec's headers. For information on how to sign the package see: http://fedoranews.org/tchung/gpg/ diff --git a/packaging/RPMS/Fedora/rabbitmq-server.spec b/packaging/RPMS/Fedora/rabbitmq-server.spec index dd12e1e5..25213816 100644 --- a/packaging/RPMS/Fedora/rabbitmq-server.spec +++ b/packaging/RPMS/Fedora/rabbitmq-server.spec @@ -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 diff --git a/packaging/debs/Debian/Makefile b/packaging/debs/Debian/Makefile index b49094e2..aeb958a7 100644 --- a/packaging/debs/Debian/Makefile +++ b/packaging/debs/Debian/Makefile @@ -20,7 +20,7 @@ package: clean cp -r debian $(UNPACKED_DIR) chmod -R a+x $(UNPACKED_DIR)/debian UNOFFICIAL_RELEASE=$(UNOFFICIAL_RELEASE) VERSION=$(VERSION) ./check-changelog.sh rabbitmq-server $(UNPACKED_DIR) - cd $(UNPACKED_DIR); dpkg-buildpackage -rfakeroot $(SIGNING) + cd $(UNPACKED_DIR); GNUPGHOME=$(GNUPG_PATH)/.gnupg dpkg-buildpackage -rfakeroot $(SIGNING) rm -rf $(UNPACKED_DIR) clean: diff --git a/packaging/debs/Debian/debian/control b/packaging/debs/Debian/debian/control index ae698e1e..df9a330b 100644 --- a/packaging/debs/Debian/debian/control +++ b/packaging/debs/Debian/debian/control @@ -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/ diff --git a/packaging/debs/Debian/debian/dirs b/packaging/debs/Debian/debian/dirs index 74ff60e2..0b3f55b9 100644 --- a/packaging/debs/Debian/debian/dirs +++ b/packaging/debs/Debian/debian/dirs @@ -1,6 +1,6 @@ usr/lib/erlang/lib usr/sbin -usr/share/linda/overrides +usr/share/man var/lib/rabbitmq/mnesia var/log/rabbitmq diff --git a/packaging/debs/Debian/debian/rules b/packaging/debs/Debian/debian/rules index 15b0d50a..6edf27c1 100644 --- a/packaging/debs/Debian/debian/rules +++ b/packaging/debs/Debian/debian/rules @@ -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 diff --git a/packaging/generic-unix/Makefile b/packaging/generic-unix/Makefile index 13257522..b3988696 100644 --- a/packaging/generic-unix/Makefile +++ b/packaging/generic-unix/Makefile @@ -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) diff --git a/packaging/windows/Makefile b/packaging/windows/Makefile index 077461c5..f9437da7 100644 --- a/packaging/windows/Makefile +++ b/packaging/windows/Makefile @@ -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) diff --git a/src/rabbit.erl b/src/rabbit.erl index e65d532b..9ab6b1a6 100644 --- a/src/rabbit.erl +++ b/src/rabbit.erl @@ -98,7 +98,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, @@ -128,9 +128,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", @@ -150,14 +150,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 () -> @@ -215,26 +213,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() -> @@ -273,7 +253,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; diff --git a/src/rabbit_access_control.erl b/src/rabbit_access_control.erl index 2be07b19..4342e15b 100644 --- a/src/rabbit_access_control.erl +++ b/src/rabbit_access_control.erl @@ -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, - _ = '_'}). diff --git a/src/rabbit_amqqueue.erl b/src/rabbit_amqqueue.erl index 63f043ba..7ce350d8 100644 --- a/src/rabbit_amqqueue.erl +++ b/src/rabbit_amqqueue.erl @@ -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 = [], diff --git a/src/rabbit_channel.erl b/src/rabbit_channel.erl index ec1d1fba..caa63b58 100644 --- a/src/rabbit_channel.erl +++ b/src/rabbit_channel.erl @@ -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), diff --git a/src/rabbit_control.erl b/src/rabbit_control.erl index ad796b61..eb24b782 100644 --- a/src/rabbit_control.erl +++ b/src/rabbit_control.erl @@ -88,17 +88,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 @@ -182,68 +171,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) -> diff --git a/src/rabbit_error_logger.erl b/src/rabbit_error_logger.erl index 0ae116bb..9220d7b4 100644 --- a/src/rabbit_error_logger.erl +++ b/src/rabbit_error_logger.erl @@ -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, diff --git a/src/rabbit_exchange.erl b/src/rabbit_exchange.erl index 113b7878..bb132a50 100644 --- a/src/rabbit_exchange.erl +++ b/src/rabbit_exchange.erl @@ -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. diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl index 927d7712..11ab0caf 100644 --- a/src/rabbit_misc.erl +++ b/src/rabbit_misc.erl @@ -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)). diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl index b8b437b0..4ae367ba 100644 --- a/src/rabbit_mnesia.erl +++ b/src/rabbit_mnesia.erl @@ -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)}]}, diff --git a/src/rabbit_node_monitor.erl b/src/rabbit_node_monitor.erl index beef5285..2fb582a9 100644 --- a/src/rabbit_node_monitor.erl +++ b/src/rabbit_node_monitor.erl @@ -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) -> diff --git a/src/rabbit_realm.erl b/src/rabbit_realm.erl deleted file mode 100644 index 4bd6db84..00000000 --- a/src/rabbit_realm.erl +++ /dev/null @@ -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])). diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl index beeb3508..6f43b08a 100644 --- a/src/rabbit_tests.erl +++ b/src/rabbit_tests.erl @@ -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 diff --git a/src/rabbit_ticket.erl b/src/rabbit_ticket.erl deleted file mode 100644 index 16475a98..00000000 --- a/src/rabbit_ticket.erl +++ /dev/null @@ -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. |