summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUILD.in2
-rw-r--r--Makefile4
-rw-r--r--codegen.py34
-rw-r--r--docs/rabbitmqctl.pod18
-rw-r--r--ebin/rabbit.app2
-rw-r--r--include/rabbit.hrl34
-rw-r--r--include/rabbit_framing_spec.hrl2
-rw-r--r--packaging/RPMS/Fedora/README.txt28
-rw-r--r--packaging/debs/Debian/Makefile2
-rw-r--r--packaging/debs/Debian/debian/control2
-rw-r--r--packaging/debs/Debian/debian/copyright6
-rw-r--r--packaging/debs/Debian/debian/dirs1
-rw-r--r--packaging/debs/Debian/debian/rules1
-rwxr-xr-xscripts/rabbitmq-multi2
-rw-r--r--scripts/rabbitmq-multi.bat4
-rwxr-xr-xscripts/rabbitmq-server2
-rw-r--r--scripts/rabbitmq-server.bat2
-rwxr-xr-xscripts/rabbitmqctl2
-rw-r--r--scripts/rabbitmqctl.bat2
-rw-r--r--src/rabbit.erl167
-rw-r--r--src/rabbit_access_control.erl124
-rw-r--r--src/rabbit_amqqueue.erl36
-rw-r--r--src/rabbit_channel.erl126
-rw-r--r--src/rabbit_control.erl82
-rw-r--r--src/rabbit_error_logger.erl5
-rw-r--r--src/rabbit_error_logger_file_h.erl74
-rw-r--r--src/rabbit_exchange.erl38
-rw-r--r--src/rabbit_misc.erl100
-rw-r--r--src/rabbit_mnesia.erl23
-rw-r--r--src/rabbit_multi.erl2
-rw-r--r--src/rabbit_node_monitor.erl1
-rw-r--r--src/rabbit_realm.erl302
-rw-r--r--src/rabbit_sasl_report_file_h.erl86
-rw-r--r--src/rabbit_tests.erl235
-rw-r--r--src/rabbit_ticket.erl131
35 files changed, 637 insertions, 1045 deletions
diff --git a/BUILD.in b/BUILD.in
index b013bc3c..0e70d0e7 100644
--- a/BUILD.in
+++ b/BUILD.in
@@ -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
diff --git a/Makefile b/Makefile
index 471c32f9..ee7bb30d 100644
--- a/Makefile
+++ b/Makefile
@@ -102,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); \
@@ -115,7 +115,7 @@ srcdist: distclean
$(MAKE) VERSION=$(VERSION) GENERIC_STAGE_DIR=dist/$(TARBALL_NAME) generic_stage
mkdir -p dist/$(TARBALL_NAME)/codegen
- cp -r $(AMQP_CODEGEN_DIR)/* dist/$(TARBALL_NAME)/codegen/.
+ cp -r $(AMQP_CODEGEN_DIR)/* dist/$(TARBALL_NAME)/codegen/
cp codegen.py Makefile dist/$(TARBALL_NAME)
cp -r scripts dist/$(TARBALL_NAME)
diff --git a/codegen.py b/codegen.py
index 242c2418..5dbc57c7 100644
--- a/codegen.py
+++ b/codegen.py
@@ -45,6 +45,22 @@ erlangTypeMap = {
'timestamp': 'timestamp',
}
+# Coming up with a proper encoding of AMQP tables in JSON is too much
+# hassle at this stage. Given that the only default value we are
+# interested in is for the empty table, we only support that.
+def convertTable(d):
+ if len(d) == 0:
+ return "[]"
+ else: raise 'Non-empty table defaults not supported', d
+
+erlangDefaultValueTypeConvMap = {
+ bool : lambda x: str(x).lower(),
+ str : lambda x: "<<\"" + x + "\">>",
+ int : lambda x: str(x),
+ float : lambda x: str(x),
+ dict: convertTable
+}
+
def erlangize(s):
s = s.replace('-', '_')
s = s.replace(' ', '_')
@@ -271,6 +287,15 @@ def genHrl(spec):
def fieldNameList(fields):
return ', '.join([erlangize(f.name) for f in fields])
+
+ def fieldNameListDefaults(fields):
+ def fillField(field):
+ result = erlangize(f.name)
+ if field.defaultvalue != None:
+ conv_fn = erlangDefaultValueTypeConvMap[type(field.defaultvalue)]
+ result += ' = ' + conv_fn(field.defaultvalue)
+ return result
+ return ', '.join([fillField(f) for f in fields])
methods = spec.allMethods()
@@ -283,23 +308,18 @@ def genHrl(spec):
print "%% Method field records."
for m in methods:
- print "-record(%s, {%s})." % (m.erlangName(), fieldNameList(m.arguments))
+ print "-record(%s, {%s})." % (m.erlangName(), fieldNameListDefaults(m.arguments))
print "%% Class property records."
for c in spec.allClasses():
print "-record('P_%s', {%s})." % (erlangize(c.name), fieldNameList(c.fields))
-#---------------------------------------------------------------------------
-
def generateErl(specPath):
genErl(AmqpSpec(specPath))
def generateHrl(specPath):
genHrl(AmqpSpec(specPath))
-
+
if __name__ == "__main__":
do_main(generateHrl, generateErl)
-
-
-
diff --git a/docs/rabbitmqctl.pod b/docs/rabbitmqctl.pod
index db31b621..b34cbca7 100644
--- a/docs/rabbitmqctl.pod
+++ b/docs/rabbitmqctl.pod
@@ -66,6 +66,19 @@ force_reset
It should only be used as a last resort if the database or cluster
configuration has been corrupted.
+rotate_logs [suffix]
+ instruct the RabbitMQ node to rotate the log files. The RabbitMQ
+ broker will attempt to append the current contents of the log file
+ to the file with the name composed of the original name and the
+ suffix. It will create a new file if such a file does not already
+ exist. When no I<suffix> is specified, the empty log file is
+ simply created at the original location; no rotation takes place.
+ When an error occurs while appending the contents of the old log
+ file, the operation behaves in the same way as if no I<suffix> was
+ specified.
+ This command might be helpful when you are e.g. writing your own
+ logrotate script and you do not want to restart the RabbitMQ node.
+
cluster I<clusternode> ...
instruct the node to become member of a cluster with the specified
nodes determined by I<clusternode> option(s).
@@ -118,6 +131,11 @@ Grant user named foo access to the virtual host called test at the
default Erlang node:
rabbitmqctl map_user_vhost foo test
+
+Append the current logs' content to the files with ".1" suffix and reopen
+them:
+
+ rabbitmqctl rotate_logs .1
=head1 SEE ALSO
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..180a0dc3 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}).
@@ -79,20 +71,12 @@
-type(r(Kind) ::
#resource{virtual_host :: vhost(),
kind :: Kind,
- name :: name()}).
--type(realm_name() :: r('realm')).
+ name :: resource_name()}).
-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/include/rabbit_framing_spec.hrl b/include/rabbit_framing_spec.hrl
index ef9ab584..e9e65092 100644
--- a/include/rabbit_framing_spec.hrl
+++ b/include/rabbit_framing_spec.hrl
@@ -46,7 +46,7 @@
-type(channel_number() :: non_neg_integer()).
%% TODO: make this more precise
-type(amqp_error() :: {bool(), non_neg_integer(), binary()}).
--type(name() :: binary()).
+-type(resource_name() :: binary()).
-type(routing_key() :: binary()).
-type(username() :: binary()).
-type(password() :: binary()).
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/debs/Debian/Makefile b/packaging/debs/Debian/Makefile
index aeb958a7..dd74c31e 100644
--- a/packaging/debs/Debian/Makefile
+++ b/packaging/debs/Debian/Makefile
@@ -18,7 +18,7 @@ package: clean
make -C ../.. check_tools
tar -zxvf $(TARBALL_DIR)/$(TARBALL)
cp -r debian $(UNPACKED_DIR)
- chmod -R a+x $(UNPACKED_DIR)/debian
+ chmod a+x $(UNPACKED_DIR)/debian/rules
UNOFFICIAL_RELEASE=$(UNOFFICIAL_RELEASE) VERSION=$(VERSION) ./check-changelog.sh rabbitmq-server $(UNPACKED_DIR)
cd $(UNPACKED_DIR); GNUPGHOME=$(GNUPG_PATH)/.gnupg dpkg-buildpackage -rfakeroot $(SIGNING)
rm -rf $(UNPACKED_DIR)
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/copyright b/packaging/debs/Debian/debian/copyright
index e16996e5..9f9f8672 100644
--- a/packaging/debs/Debian/debian/copyright
+++ b/packaging/debs/Debian/debian/copyright
@@ -5,7 +5,7 @@ It was downloaded from http://www.rabbitmq.com/
Upstream Author: The RabbitMQ team <info@rabbitmq.com>
-Copyright: 2006-2008 LShift Ltd.
+Copyright: 2006-2008 Rabbit Technologies Ltd.
License:
The RabbitMQ server is licensed under the MPL.
@@ -485,7 +485,7 @@ EXHIBIT A -Mozilla Public License.
If you have any questions regarding licensing, please contact us at
info@rabbitmq.com.
-The Debian packaging is (C) 2007, Tony Garnock-Jones <tonyg@rabbitmq.com> and
-is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+The Debian packaging is (C) 2007-2008, Rabbit Technologies Ltd. <info@rabbitmq.com>
+and is licensed under the MPL 1.1, see above.
diff --git a/packaging/debs/Debian/debian/dirs b/packaging/debs/Debian/debian/dirs
index 48db317f..0b3f55b9 100644
--- a/packaging/debs/Debian/debian/dirs
+++ b/packaging/debs/Debian/debian/dirs
@@ -1,7 +1,6 @@
usr/lib/erlang/lib
usr/sbin
usr/share/man
-usr/share/linda/overrides
var/lib/rabbitmq/mnesia
var/log/rabbitmq
diff --git a/packaging/debs/Debian/debian/rules b/packaging/debs/Debian/debian/rules
index e230aec5..6edf27c1 100644
--- a/packaging/debs/Debian/debian/rules
+++ b/packaging/debs/Debian/debian/rules
@@ -16,4 +16,3 @@ install/rabbitmq-server::
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/scripts/rabbitmq-multi b/scripts/rabbitmq-multi
index 4709ca0b..5e4f4b38 100755
--- a/scripts/rabbitmq-multi
+++ b/scripts/rabbitmq-multi
@@ -36,7 +36,7 @@ SCRIPT_HOME=$(dirname $0)
export NODENAME NODE_IP_ADDRESS NODE_PORT SCRIPT_HOME PIDS_FILE
exec erl \
- -pa ../ebin \
+ -pa "`dirname $0`/../ebin" \
-noinput \
-hidden \
${ERL_ARGS} \
diff --git a/scripts/rabbitmq-multi.bat b/scripts/rabbitmq-multi.bat
index 34e34ef9..819c99af 100644
--- a/scripts/rabbitmq-multi.bat
+++ b/scripts/rabbitmq-multi.bat
@@ -41,7 +41,7 @@ if "%NODE_PORT%"=="" (
)
set PIDS_FILE=%RABBITMQ_BASE%\rabbitmq.pids
-set SCRIPT_HOME=.
+set SCRIPT_HOME=%~dp0%
if "%ERLANG_HOME%"=="" (
set ERLANG_HOME=%~dp0%..\..\..
@@ -59,5 +59,5 @@ if not exist "%ERLANG_HOME%\bin\erl.exe" (
exit /B
)
-"%ERLANG_HOME%\bin\erl.exe" -pa ../ebin -noinput -hidden -sname rabbitmq_multi -s rabbit_multi %START_ARGS% -extra %*
+"%ERLANG_HOME%\bin\erl.exe" -pa "%~dp0..\ebin" -noinput -hidden -sname rabbitmq_multi -s rabbit_multi %START_ARGS% -extra %*
diff --git a/scripts/rabbitmq-server b/scripts/rabbitmq-server
index a44dd6da..e5fb93cc 100755
--- a/scripts/rabbitmq-server
+++ b/scripts/rabbitmq-server
@@ -51,7 +51,7 @@ else
fi
erl \
- -pa $(dirname $0)/../ebin \
+ -pa "`dirname $0`/../ebin" \
${START_RABBIT} \
-sname ${NODENAME} \
-boot start_sasl \
diff --git a/scripts/rabbitmq-server.bat b/scripts/rabbitmq-server.bat
index 46f4bd92..8b06c0b4 100644
--- a/scripts/rabbitmq-server.bat
+++ b/scripts/rabbitmq-server.bat
@@ -92,7 +92,7 @@ set CLUSTER_CONFIG=-rabbit cluster_config \""%CLUSTER_CONFIG_FILE:\=/%"\"
set MNESIA_DIR=%MNESIA_BASE%/%NODENAME%-mnesia
"%ERLANG_HOME%\bin\erl.exe" ^
--pa ..\ebin ^
+-pa "%~dp0..\ebin" ^
-noinput ^
-boot start_sasl ^
-sname %NODENAME% ^
diff --git a/scripts/rabbitmqctl b/scripts/rabbitmqctl
index eb359dad..419dcf63 100755
--- a/scripts/rabbitmqctl
+++ b/scripts/rabbitmqctl
@@ -31,7 +31,7 @@ ERL_ARGS=
MNESIA_DIR=${MNESIA_BASE}/${NODENAME}
exec erl \
- -pa ../ebin \
+ -pa "`dirname $0`/../ebin" \
-noinput \
-hidden \
${ERL_ARGS} \
diff --git a/scripts/rabbitmqctl.bat b/scripts/rabbitmqctl.bat
index b34adebe..1ee7e825 100644
--- a/scripts/rabbitmqctl.bat
+++ b/scripts/rabbitmqctl.bat
@@ -40,4 +40,4 @@ if not exist "%ERLANG_HOME%\bin\erl.exe" (
exit /B
)
-"%ERLANG_HOME%\bin\erl.exe" -pa ..\ebin -noinput -hidden -sname rabbitmqctl -s rabbit_control -extra %*
+"%ERLANG_HOME%\bin\erl.exe" -pa "%~dp0..\ebin" -noinput -hidden -sname rabbitmqctl -s rabbit_control -extra %*
diff --git a/src/rabbit.erl b/src/rabbit.erl
index e65d532b..c6ef1749 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -27,10 +27,12 @@
-behaviour(application).
--export([start/0, stop/0, stop_and_halt/0, status/0]).
+-export([start/0, stop/0, stop_and_halt/0, status/0, rotate_logs/1]).
-export([start/2, stop/1]).
+-export([log_location/1]).
+
-import(application).
-import(mnesia).
-import(lists).
@@ -46,13 +48,18 @@
-ifdef(use_specs).
+-type(log_location() :: 'tty' | 'undefined' | string()).
+-type(file_suffix() :: binary()).
+
-spec(start/0 :: () -> 'ok').
-spec(stop/0 :: () -> 'ok').
-spec(stop_and_halt/0 :: () -> 'ok').
+-spec(rotate_logs/1 :: (file_suffix()) -> 'ok' | {'error', any()}).
-spec(status/0 :: () ->
[{running_applications, [{atom(), string(), string()}]} |
{nodes, [node()]} |
{running_nodes, [node()]}]).
+-spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()).
-endif.
@@ -60,7 +67,7 @@
start() ->
try
- ok = ensure_working_log_config(),
+ ok = ensure_working_log_handlers(),
ok = rabbit_mnesia:ensure_mnesia_dir(),
ok = start_applications(?APPS)
after
@@ -85,6 +92,15 @@ status() ->
[{running_applications, application:which_applications()}] ++
rabbit_mnesia:status().
+rotate_logs(BinarySuffix) ->
+ Suffix = binary_to_list(BinarySuffix),
+ log_rotation_result(rotate_logs(log_location(kernel),
+ Suffix,
+ rabbit_error_logger_file_h),
+ rotate_logs(log_location(sasl),
+ Suffix,
+ rabbit_sasl_report_file_h)).
+
%%--------------------------------------------------------------------
manage_applications(Iterate, Do, Undo, SkipError, ErrorTag, Apps) ->
@@ -98,7 +114,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 +144,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 +166,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 () ->
@@ -188,6 +202,21 @@ stop(_State) ->
%---------------------------------------------------------------------------
+log_location(Type) ->
+ case application:get_env(Type, case Type of
+ kernel -> error_logger;
+ sasl -> sasl_error_logger
+ end) of
+ {ok, {file, File}} -> File;
+ {ok, false} -> undefined;
+ {ok, tty} -> tty;
+ {ok, silent} -> undefined;
+ {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}});
+ _ -> undefined
+ end.
+
+%---------------------------------------------------------------------------
+
print_banner() ->
{ok, Product} = application:get_key(id),
{ok, Version} = application:get_key(vsn),
@@ -196,7 +225,9 @@ print_banner() ->
?PROTOCOL_VERSION_MAJOR, ?PROTOCOL_VERSION_MINOR,
?COPYRIGHT_MESSAGE, ?INFORMATION_MESSAGE]),
io:format("Logging to ~p~nSASL logging to ~p~n~n",
- [error_log_location(), sasl_log_location()]).
+ [log_location(kernel), log_location(sasl)]).
+
+
start_child(Mod) ->
{ok,_} = supervisor:start_child(rabbit_sup,
@@ -204,6 +235,43 @@ start_child(Mod) ->
transient, 100, worker, [Mod]}),
ok.
+ensure_working_log_handlers() ->
+ Handlers = gen_event:which_handlers(error_logger),
+ ok = ensure_working_log_handler(error_logger_file_h,
+ rabbit_error_logger_file_h,
+ error_logger_tty_h,
+ log_location(kernel),
+ Handlers),
+
+ ok = ensure_working_log_handler(sasl_report_file_h,
+ rabbit_sasl_report_file_h,
+ sasl_report_tty_h,
+ log_location(sasl),
+ Handlers),
+ ok.
+
+ensure_working_log_handler(OldFHandler, NewFHandler, TTYHandler,
+ LogLocation, Handlers) ->
+ case LogLocation of
+ undefined -> ok;
+ tty -> case lists:member(TTYHandler, Handlers) of
+ true -> ok;
+ false ->
+ throw({error, {cannot_log_to_tty,
+ TTYHandler, not_installed}})
+ end;
+ _ -> case lists:member(NewFHandler, Handlers) of
+ true -> ok;
+ false -> case rotate_logs(LogLocation, "",
+ OldFHandler, NewFHandler) of
+ ok -> ok;
+ {error, Reason} ->
+ throw({error, {cannot_log_to_file,
+ LogLocation, Reason}})
+ end
+ end
+ end.
+
maybe_insert_default_data() ->
case rabbit_mnesia:is_db_empty() of
true -> insert_default_data();
@@ -215,26 +283,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() ->
@@ -243,40 +293,25 @@ start_builtin_amq_applications() ->
%%restart
ok.
-ensure_working_log_config() ->
- case error_logger:logfile(filename) of
- {error, no_log_file} ->
- %% either no log file was configured or opening it failed.
- case application:get_env(kernel, error_logger) of
- {ok, {file, Filename}} ->
- case filelib:ensure_dir(Filename) of
- ok -> ok;
- {error, Reason1} ->
- throw({error, {cannot_log_to_file,
- Filename, Reason1}})
- end,
- case error_logger:logfile({open, Filename}) of
- ok -> ok;
- {error, Reason2} ->
- throw({error, {cannot_log_to_file,
- Filename, Reason2}})
- end;
- _ -> ok
- end;
- _Filename -> ok
- end.
-
-error_log_location() ->
- case error_logger:logfile(filename) of
- {error,no_log_file} -> tty;
- File -> File
+rotate_logs(File, Suffix, Handler) ->
+ rotate_logs(File, Suffix, Handler, Handler).
+
+rotate_logs(File, Suffix, OldHandler, NewHandler) ->
+ case File of
+ undefined -> ok;
+ tty -> ok;
+ _ -> gen_event:swap_handler(
+ error_logger,
+ {OldHandler, swap},
+ {NewHandler, {File, Suffix}})
end.
-sasl_log_location() ->
- case application:get_env(sasl, sasl_error_logger) of
- {ok, {file, File}} -> File;
- {ok, false} -> undefined;
- {ok, tty} -> tty;
- {ok, Bad} -> throw({error, {cannot_log_to_file, Bad}});
- _ -> undefined
- end.
+log_rotation_result({error, MainLogError}, {error, SaslLogError}) ->
+ {error, {{cannot_rotate_main_logs, MainLogError},
+ {cannot_rotate_sasl_logs, SaslLogError}}};
+log_rotation_result({error, MainLogError}, ok) ->
+ {error, {cannot_rotate_main_logs, MainLogError}};
+log_rotation_result(ok, {error, SaslLogError}) ->
+ {error, {cannot_rotate_sasl_logs, SaslLogError}};
+log_rotation_result(ok, ok) ->
+ ok.
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..5cc07aed 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..bc588279 100644
--- a/src/rabbit_control.erl
+++ b/src/rabbit_control.erl
@@ -73,6 +73,7 @@ Available commands:
force_reset
cluster <ClusterNode> ...
status
+ rotate_logs [Suffix]
add_user <UserName> <Password>
delete_user <UserName>
@@ -88,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
@@ -140,6 +130,13 @@ action(status, Node, []) ->
io:format("~n~p~n", [Res]),
ok;
+action(rotate_logs, Node, []) ->
+ io:format("Reopening logs for node ~p ...", [Node]),
+ call(Node, {rabbit, rotate_logs, [""]});
+action(rotate_logs, Node, Args = [Suffix]) ->
+ io:format("Rotating logs to files with suffix ~p ...", [Suffix]),
+ call(Node, {rabbit, rotate_logs, Args});
+
action(add_user, Node, Args = [Username, _Password]) ->
io:format("Creating user ~p ...", [Username]),
call(Node, {rabbit_access_control, add_user, Args});
@@ -182,68 +179,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_error_logger_file_h.erl b/src/rabbit_error_logger_file_h.erl
new file mode 100644
index 00000000..d67b02ef
--- /dev/null
+++ b/src/rabbit_error_logger_file_h.erl
@@ -0,0 +1,74 @@
+%% 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_error_logger_file_h).
+
+-behaviour(gen_event).
+
+-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
+
+%% rabbit_error_logger_file_h is a wrapper around the error_logger_file_h
+%% module because the original's init/1 does not match properly
+%% with the result of closing the old handler when swapping handlers.
+%% The first init/1 additionally allows for simple log rotation
+%% when the suffix is not the empty string.
+
+%% Used only when swapping handlers in log rotation
+init({{File, Suffix}, []}) ->
+ case rabbit_misc:append_file(File, Suffix) of
+ ok -> ok;
+ {error, Error} ->
+ rabbit_log:error("Failed to append contents of " ++
+ "log file '~s' to '~s':~n~p~n",
+ [File, [File, Suffix], Error])
+ end,
+ init(File);
+%% Used only when swapping handlers and the original handler
+%% failed to terminate or was never installed
+init({{File, _}, error}) ->
+ init(File);
+%% Used only when swapping handlers without performing
+%% log rotation
+init({File, []}) ->
+ init(File);
+init({_File, _Type} = FileInfo) ->
+ error_logger_file_h:init(FileInfo);
+init(File) ->
+ error_logger_file_h:init(File).
+
+handle_event(Event, State) ->
+ error_logger_file_h:handle_event(Event, State).
+
+handle_info(Event, State) ->
+ error_logger_file_h:handle_info(Event, State).
+
+handle_call(Event, State) ->
+ error_logger_file_h:handle_call(Event, State).
+
+terminate(Reason, State) ->
+ error_logger_file_h:terminate(Reason, State).
+
+code_change(OldVsn, State, Extra) ->
+ error_logger_file_h:code_change(OldVsn, State, Extra).
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..3e4ed8f3 100644
--- a/src/rabbit_misc.erl
+++ b/src/rabbit_misc.erl
@@ -26,23 +26,23 @@
-module(rabbit_misc).
-include("rabbit.hrl").
-include("rabbit_framing.hrl").
+-include_lib("kernel/include/file.hrl").
-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]).
-export([intersperse/2, upmap/2, map_in_order/2]).
-export([guid/0, string_guid/1, binstring_guid/1]).
-export([dirty_read_all/1, dirty_foreach_key/2, dirty_dump_log/1]).
+-export([append_file/2]).
-import(mnesia).
-import(lists).
@@ -64,32 +64,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, resource_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()).
@@ -98,6 +94,7 @@
-spec(dirty_foreach_key/2 :: (fun ((any()) -> any()), atom()) ->
'ok' | 'aborted').
-spec(dirty_dump_log/1 :: (string()) -> 'ok' | {'error', any()}).
+-spec(append_file/2 :: (string(), string()) -> 'ok' | {'error', any()}).
-endif.
@@ -128,24 +125,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 +159,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 +217,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)).
@@ -389,3 +336,24 @@ dirty_dump_log1(LH, {K, Terms}) ->
dirty_dump_log1(LH, {K, Terms, BadBytes}) ->
io:format("Bad Chunk, ~p: ~p~n", [BadBytes, Terms]),
dirty_dump_log1(LH, disk_log:chunk(LH, K)).
+
+
+append_file(File, Suffix) ->
+ case file:read_file_info(File) of
+ {ok, FInfo} -> append_file(File, FInfo#file_info.size, Suffix);
+ {error, enoent} -> append_file(File, 0, Suffix);
+ Error -> Error
+ end.
+
+append_file(_, _, "") ->
+ ok;
+append_file(File, 0, Suffix) ->
+ case file:open([File, Suffix], [append]) of
+ {ok, Fd} -> file:close(Fd);
+ Error -> Error
+ end;
+append_file(File, _, Suffix) ->
+ case file:read_file(File) of
+ {ok, Data} -> file:write_file([File, Suffix], Data, [append]);
+ Error -> Error
+ end.
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_multi.erl b/src/rabbit_multi.erl
index cd92f1ac..bde69336 100644
--- a/src/rabbit_multi.erl
+++ b/src/rabbit_multi.erl
@@ -233,7 +233,7 @@ stop_node({Node, Pid}, RpcTimeout) ->
rpc:call(Node, rabbit, stop_and_halt, []),
case kill_wait(Pid, RpcTimeout, false) of
false -> kill_wait(Pid, RpcTimeout, true);
- true -> ok
+ true -> ok
end,
io:format("OK~n", []).
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_sasl_report_file_h.erl b/src/rabbit_sasl_report_file_h.erl
new file mode 100644
index 00000000..3374d63d
--- /dev/null
+++ b/src/rabbit_sasl_report_file_h.erl
@@ -0,0 +1,86 @@
+%% 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_sasl_report_file_h).
+
+-behaviour(gen_event).
+
+-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
+
+%% rabbit_sasl_report_file_h is a wrapper around the sasl_report_file_h
+%% module because the original's init/1 does not match properly
+%% with the result of closing the old handler when swapping handlers.
+%% The first init/1 additionally allows for simple log rotation
+%% when the suffix is not the empty string.
+
+%% Used only when swapping handlers and performing
+%% log rotation
+init({{File, Suffix}, []}) ->
+ case rabbit_misc:append_file(File, Suffix) of
+ ok -> ok;
+ {error, Error} ->
+ rabbit_log:error("Failed to append contents of " ++
+ "sasl log file '~s' to '~s':~n~p~n",
+ [File, [File, Suffix], Error])
+ end,
+ init(File);
+%% Used only when swapping handlers and the original handler
+%% failed to terminate or was never installed
+init({{File, _}, error}) ->
+ init(File);
+%% Used only when swapping handlers without
+%% doing any log rotation
+init({File, []}) ->
+ init(File);
+init({_File, _Type} = FileInfo) ->
+ sasl_report_file_h:init(FileInfo);
+init(File) ->
+ sasl_report_file_h:init({File, sasl_error_logger_type()}).
+
+handle_event(Event, State) ->
+ sasl_report_file_h:handle_event(Event, State).
+
+handle_info(Event, State) ->
+ sasl_report_file_h:handle_info(Event, State).
+
+handle_call(Event, State) ->
+ sasl_report_file_h:handle_call(Event, State).
+
+terminate(Reason, State) ->
+ sasl_report_file_h:terminate(Reason, State).
+
+code_change(OldVsn, State, Extra) ->
+ sasl_report_file_h:code_change(OldVsn, State, Extra).
+
+%%----------------------------------------------------------------------
+
+sasl_error_logger_type() ->
+ case application:get_env(sasl, errlog_type) of
+ {ok, error} -> error;
+ {ok, progress} -> progress;
+ {ok, all} -> all;
+ {ok, Bad} -> throw({error, {wrong_errlog_type, Bad}});
+ _ -> all
+ end.
diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl
index beeb3508..fff02d73 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -29,6 +29,8 @@
-import(lists).
+-include_lib("kernel/include/file.hrl").
+
test_content_prop_roundtrip(Datum, Binary) ->
Types = [element(1, E) || E <- Datum],
Values = [element(2, E) || E <- Datum],
@@ -38,7 +40,9 @@ test_content_prop_roundtrip(Datum, Binary) ->
all_tests() ->
passed = test_parsing(),
passed = test_topic_matching(),
+ passed = test_log_management(),
passed = test_app_management(),
+ passed = test_log_management_during_startup(),
passed = test_cluster_management(),
passed = test_user_management(),
passed.
@@ -136,6 +140,134 @@ test_app_management() ->
ok = control_action(status, []),
passed.
+test_log_management() ->
+ MainLog = rabbit:log_location(kernel),
+ SaslLog = rabbit:log_location(sasl),
+ Suffix = ".1",
+
+ %% prepare basic logs
+ file:delete([MainLog, Suffix]),
+ file:delete([SaslLog, Suffix]),
+
+ %% simple logs reopening
+ ok = control_action(rotate_logs, []),
+ [true, true] = empty_files([MainLog, SaslLog]),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% simple log rotation
+ ok = control_action(rotate_logs, [Suffix]),
+ [true, true] = non_empty_files([[MainLog, Suffix], [SaslLog, Suffix]]),
+ [true, true] = empty_files([MainLog, SaslLog]),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% reopening logs with log rotation performed first
+ ok = clean_logs([MainLog, SaslLog], Suffix),
+ ok = control_action(rotate_logs, []),
+ ok = file:rename(MainLog, [MainLog, Suffix]),
+ ok = file:rename(SaslLog, [SaslLog, Suffix]),
+ ok = test_logs_working([MainLog, Suffix], [SaslLog, Suffix]),
+ ok = control_action(rotate_logs, []),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% log rotation on empty file
+ ok = clean_logs([MainLog, SaslLog], Suffix),
+ ok = control_action(rotate_logs, []),
+ ok = control_action(rotate_logs, [Suffix]),
+ [true, true] = empty_files([[MainLog, Suffix], [SaslLog, Suffix]]),
+
+ %% original main log file is not writable
+ ok = make_files_non_writable([MainLog]),
+ {error, {cannot_rotate_main_logs, _}} = control_action(rotate_logs, []),
+ ok = clean_logs([MainLog], Suffix),
+ ok = add_log_handlers([{rabbit_error_logger_file_h, MainLog}]),
+
+ %% original sasl log file is not writable
+ ok = make_files_non_writable([SaslLog]),
+ {error, {cannot_rotate_sasl_logs, _}} = control_action(rotate_logs, []),
+ ok = clean_logs([SaslLog], Suffix),
+ ok = add_log_handlers([{rabbit_sasl_report_file_h, SaslLog}]),
+
+ %% logs with suffix are not writable
+ ok = control_action(rotate_logs, [Suffix]),
+ ok = make_files_non_writable([[MainLog, Suffix], [SaslLog, Suffix]]),
+ ok = control_action(rotate_logs, [Suffix]),
+ ok = test_logs_working(MainLog, SaslLog),
+
+ %% original log files are not writable
+ ok = make_files_non_writable([MainLog, SaslLog]),
+ {error, {{cannot_rotate_main_logs, _},
+ {cannot_rotate_sasl_logs, _}}} = control_action(rotate_logs, []),
+
+ %% logging directed to tty (handlers were removed in last test)
+ ok = clean_logs([MainLog, SaslLog], Suffix),
+ ok = application:set_env(sasl, sasl_error_logger, tty),
+ ok = application:set_env(kernel, error_logger, tty),
+ ok = control_action(rotate_logs, []),
+ [{error, enoent}, {error, enoent}] = empty_files([MainLog, SaslLog]),
+
+ %% rotate logs when logging is turned off
+ ok = application:set_env(sasl, sasl_error_logger, false),
+ ok = application:set_env(kernel, error_logger, silent),
+ ok = control_action(rotate_logs, []),
+ [{error, enoent}, {error, enoent}] = empty_files([MainLog, SaslLog]),
+
+ %% cleanup
+ ok = application:set_env(sasl, sasl_error_logger, {file, SaslLog}),
+ ok = application:set_env(kernel, error_logger, {file, MainLog}),
+ ok = add_log_handlers([{rabbit_error_logger_file_h, MainLog},
+ {rabbit_sasl_report_file_h, SaslLog}]),
+ passed.
+
+test_log_management_during_startup() ->
+ MainLog = rabbit:log_location(kernel),
+ SaslLog = rabbit:log_location(sasl),
+
+ %% start application with simple tty logging
+ ok = control_action(stop_app, []),
+ ok = application:set_env(kernel, error_logger, tty),
+ ok = application:set_env(sasl, sasl_error_logger, tty),
+ ok = add_log_handlers([{error_logger_tty_h, []},
+ {sasl_report_tty_h, []}]),
+ ok = control_action(start_app, []),
+
+ %% start application with tty logging and
+ %% proper handlers not installed
+ ok = control_action(stop_app, []),
+ ok = error_logger:tty(false),
+ ok = delete_log_handlers([sasl_report_tty_h]),
+ ok = case catch control_action(start_app, []) of
+ ok -> exit(got_success_but_expected_failure);
+ {error, {cannot_log_to_tty, _, _}} -> ok
+ end,
+
+ %% fix sasl logging
+ ok = application:set_env(sasl, sasl_error_logger,
+ {file, SaslLog}),
+
+ %% start application with logging to invalid directory
+ TmpLog = "/tmp/rabbit-tests/test.log",
+ file:delete(TmpLog),
+ ok = application:set_env(kernel, error_logger, {file, TmpLog}),
+
+ ok = delete_log_handlers([rabbit_error_logger_file_h]),
+ ok = add_log_handlers([{error_logger_file_h, MainLog}]),
+ ok = case catch control_action(start_app, []) of
+ ok -> exit(got_success_but_expected_failure);
+ {error, {cannot_log_to_file, _, _}} -> ok
+ end,
+
+ %% start application with standard error_logger_file_h
+ %% handler not installed
+ ok = application:set_env(kernel, error_logger, {file, MainLog}),
+ ok = control_action(start_app, []),
+ ok = control_action(stop_app, []),
+
+ %% start application with standard sasl handler not installed
+ %% and rabbit main log handler installed correctly
+ ok = delete_log_handlers([rabbit_sasl_report_file_h]),
+ ok = control_action(start_app, []),
+ passed.
+
test_cluster_management() ->
%% 'cluster' and 'reset' should only work if the app is stopped
@@ -203,7 +335,6 @@ test_cluster_management() ->
end,
ok = control_action(start_app, []),
-
passed.
test_cluster_management2(SecondaryNode) ->
@@ -284,31 +415,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 +439,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 +450,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
@@ -380,6 +460,8 @@ test_user_management() ->
passed.
+%---------------------------------------------------------------------
+
control_action(Command, Args) -> control_action(Command, node(), Args).
control_action(Command, Node, Args) ->
@@ -391,3 +473,52 @@ control_action(Command, Node, Args) ->
io:format("failed.~n"),
Other
end.
+
+empty_files(Files) ->
+ [case file:read_file_info(File) of
+ {ok, FInfo} -> FInfo#file_info.size == 0;
+ Error -> Error
+ end || File <- Files].
+
+non_empty_files(Files) ->
+ [case EmptyFile of
+ {error, Reason} -> {error, Reason};
+ _ -> not(EmptyFile)
+ end || EmptyFile <- empty_files(Files)].
+
+test_logs_working(MainLogFile, SaslLogFile) ->
+ ok = rabbit_log:error("foo bar"),
+ ok = error_logger:error_report(crash_report, [foo, bar]),
+ %% give the error loggers some time to catch up
+ timer:sleep(50),
+ [true, true] = non_empty_files([MainLogFile, SaslLogFile]),
+ ok.
+
+clean_logs(Files, Suffix) ->
+ [begin
+ ok = delete_file(File),
+ ok = delete_file([File, Suffix])
+ end || File <- Files],
+ ok.
+
+delete_file(File) ->
+ case file:delete(File) of
+ ok -> ok;
+ {error, enoent} -> ok;
+ Error -> Error
+ end.
+
+make_files_non_writable(Files) ->
+ [ok = file:write_file_info(File, #file_info{mode=0}) ||
+ File <- Files],
+ ok.
+
+add_log_handlers(Handlers) ->
+ [ok = error_logger:add_report_handler(Handler, Args) ||
+ {Handler, Args} <- Handlers],
+ ok.
+
+delete_log_handlers(Handlers) ->
+ [[] = error_logger:delete_report_handler(Handler) ||
+ Handler <- Handlers],
+ ok.
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.