summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--docs/rabbitmq-echopid.xml71
-rw-r--r--docs/rabbitmqctl.1.xml7
-rw-r--r--ebin/rabbit_app.in1
-rw-r--r--packaging/macports/Portfile.in9
-rw-r--r--packaging/windows/Makefile3
-rw-r--r--scripts/rabbitmq-echopid.bat49
-rw-r--r--src/rabbit.erl18
-rw-r--r--src/rabbit_misc.erl15
-rw-r--r--src/rabbit_mnesia.erl10
-rw-r--r--src/rabbit_reader.erl20
-rw-r--r--src/rabbit_ssl.erl41
-rw-r--r--src/rabbit_tests.erl15
13 files changed, 226 insertions, 39 deletions
diff --git a/Makefile b/Makefile
index 31c71dd44b..92d9fa82f0 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ BEAM_TARGETS=$(patsubst $(SOURCE_DIR)/%.erl, $(EBIN_DIR)/%.beam, $(SOURCES))
TARGETS=$(EBIN_DIR)/rabbit.app $(INCLUDE_DIR)/rabbit_framing.hrl $(BEAM_TARGETS) plugins
WEB_URL=http://www.rabbitmq.com/
MANPAGES=$(patsubst %.xml, %.gz, $(wildcard $(DOCS_DIR)/*.[0-9].xml))
-WEB_MANPAGES=$(patsubst %.xml, %.man.xml, $(wildcard $(DOCS_DIR)/*.[0-9].xml) $(DOCS_DIR)/rabbitmq-service.xml)
+WEB_MANPAGES=$(patsubst %.xml, %.man.xml, $(wildcard $(DOCS_DIR)/*.[0-9].xml) $(DOCS_DIR)/rabbitmq-service.xml $(DOCS_DIR)/rabbitmq-echopid.xml)
USAGES_XML=$(DOCS_DIR)/rabbitmqctl.1.xml $(DOCS_DIR)/rabbitmq-plugins.1.xml
USAGES_ERL=$(foreach XML, $(USAGES_XML), $(call usage_xml_to_erl, $(XML)))
QC_MODULES := rabbit_backing_queue_qc
@@ -347,10 +347,10 @@ $(foreach XML,$(USAGES_XML),$(eval $(call usage_dep, $(XML))))
# Note that all targets which depend on clean must have clean in their
# name. Also any target that doesn't depend on clean should not have
# clean in its name, unless you know that you don't need any of the
-# automatic dependency generation for that target (eg cleandb).
+# automatic dependency generation for that target (e.g. cleandb).
# We want to load the dep file if *any* target *doesn't* contain
-# "clean" - i.e. if removing all clean-like targets leaves something
+# "clean" - i.e. if removing all clean-like targets leaves something.
ifeq "$(MAKECMDGOALS)" ""
TESTABLEGOALS:=$(.DEFAULT_GOAL)
diff --git a/docs/rabbitmq-echopid.xml b/docs/rabbitmq-echopid.xml
new file mode 100644
index 0000000000..d3dcea521b
--- /dev/null
+++ b/docs/rabbitmq-echopid.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.docbook.org/xml/4.5/docbookx.dtd">
+<refentry lang="en">
+ <refentryinfo>
+ <productname>RabbitMQ Server</productname>
+ <authorgroup>
+ <corpauthor>The RabbitMQ Team &lt;<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>&gt;</corpauthor>
+ </authorgroup>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>rabbitmq-echopid.bat</refentrytitle>
+ <refmiscinfo class="manual">RabbitMQ Server</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>rabbitmq-echopid.bat</refname>
+ <refpurpose>return the process id of the Erlang runtime hosting RabbitMQ</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>rabbitmq-echopid.bat</command>
+ <arg choice="req">sname</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+ <para>
+ 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.
+ </para>
+ <para>
+ Running <command>rabbitmq-echopid</command> will attempt to
+ discover and echo the process id (PID) of the Erlang runtime
+ process (erl.exe) that is hosting RabbitMQ. To allow erl.exe
+ time to start up and load RabbitMQ, the script will wait for
+ ten seconds before timing out if a suitable PID cannot be
+ found.
+ </para>
+ <para>
+ If a PID is discovered, the script will echo it to stdout
+ before exiting with a ERRORLEVEL of 0. If no PID is
+ discovered before the timeout, nothing is written to stdout
+ and the script exits setting ERRORLEVEL to 1.
+ </para>
+ <para>
+ Note that this script only exists on Windows due to the need
+ to wait for erl.exe and possibly time-out. To obtain the PID
+ on Unix set RABBITMQ_PID_FILE before starting
+ rabbitmq-server and do not use "-detached".
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+ <variablelist>
+ <varlistentry>
+ <term><cmdsynopsis><arg choice="req">sname</arg></cmdsynopsis></term>
+ <listitem>
+ <para role="usage">
+The short-name form of the RabbitMQ node name.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+</refentry>
diff --git a/docs/rabbitmqctl.1.xml b/docs/rabbitmqctl.1.xml
index c1c51f9f8b..3cfe0adf7a 100644
--- a/docs/rabbitmqctl.1.xml
+++ b/docs/rabbitmqctl.1.xml
@@ -1420,8 +1420,11 @@
<variablelist>
<varlistentry>
<term>fraction</term>
- <listitem><para>The new memory threshhold fraction at which flow control is triggered, as a
- floating point number between 0.0 and 1.0 with a mandatory fractional part.</para></listitem>
+ <listitem><para>
+ The new memory threshold fraction at which flow
+ control is triggered, as a floating point number
+ greater than or equal to 0.
+ </para></listitem>
</varlistentry>
</variablelist>
</listitem>
diff --git a/ebin/rabbit_app.in b/ebin/rabbit_app.in
index 2fee1114aa..fd19051d27 100644
--- a/ebin/rabbit_app.in
+++ b/ebin/rabbit_app.in
@@ -38,6 +38,7 @@
{delegate_count, 16},
{trace_vhosts, []},
{log_levels, [{connection, info}]},
+ {ssl_cert_login_from, distinguished_name},
{tcp_listen_options, [binary,
{packet, raw},
{reuseaddr, true},
diff --git a/packaging/macports/Portfile.in b/packaging/macports/Portfile.in
index 360fb394eb..cde02b1aa9 100644
--- a/packaging/macports/Portfile.in
+++ b/packaging/macports/Portfile.in
@@ -48,6 +48,7 @@ set serveruser rabbitmq
set servergroup rabbitmq
set serverhome ${prefix}/var/lib/rabbitmq
set logdir ${prefix}/var/log/rabbitmq
+set confdir ${prefix}/etc/rabbitmq
set mnesiadbdir ${prefix}/var/lib/rabbitmq/mnesia
set plistloc ${prefix}/etc/LaunchDaemons/org.macports.rabbitmq-server
set sbindir ${destroot}${prefix}/lib/rabbitmq/bin
@@ -74,6 +75,7 @@ destroot.destdir \
MAN_DIR=${destroot}${prefix}/share/man
destroot.keepdirs \
+ ${destroot}${confdir} \
${destroot}${logdir} \
${destroot}${mnesiadbdir}
@@ -83,17 +85,16 @@ pre-destroot {
}
post-destroot {
+ xinstall -d -m 775 ${destroot}${confdir}
xinstall -d -g [existsgroup ${servergroup}] -m 775 ${destroot}${logdir}
xinstall -d -g [existsgroup ${servergroup}] -m 775 ${destroot}${serverhome}
xinstall -d -g [existsgroup ${servergroup}] -m 775 ${destroot}${mnesiadbdir}
- reinplace -E "s:(/etc/rabbitmq/rabbitmq):${prefix}\\1:g" \
+ reinplace -E "s: (/etc/rabbitmq/rabbitmq): ${prefix}\\1:g" \
${realsbin}/rabbitmq-env
foreach var {CONFIG_FILE LOG_BASE MNESIA_BASE ENABLED_PLUGINS_FILE} {
reinplace -E "s:^($var)=/:\\1=${prefix}/:" \
- ${realsbin}/rabbitmq-server \
- ${realsbin}/rabbitmqctl \
- ${realsbin}/rabbitmq-plugins
+ ${realsbin}/rabbitmq-env
}
xinstall -m 555 ${filespath}/rabbitmq-script-wrapper \
diff --git a/packaging/windows/Makefile b/packaging/windows/Makefile
index 828cf00050..a910941b6c 100644
--- a/packaging/windows/Makefile
+++ b/packaging/windows/Makefile
@@ -26,6 +26,9 @@ dist:
elinks -dump -no-references -no-numbering rabbitmq-service.html \
> $(TARGET_DIR)/readme-service.txt
todos $(TARGET_DIR)/readme-service.txt
+ todos $(TARGET_DIR)/INSTALL
+ todos $(TARGET_DIR)/LICENSE*
+ todos $(TARGET_DIR)/plugins/README.txt
rm -rf $(TARGET_DIR)/plugins-src
zip -q -r $(TARGET_ZIP).zip $(TARGET_DIR)
rm -rf $(TARGET_DIR) rabbitmq-service.html
diff --git a/scripts/rabbitmq-echopid.bat b/scripts/rabbitmq-echopid.bat
new file mode 100644
index 0000000000..5c652c30c0
--- /dev/null
+++ b/scripts/rabbitmq-echopid.bat
@@ -0,0 +1,49 @@
+@echo off
+
+REM Usage: rabbitmq-echopid.bat <rabbitmq_nodename>
+REM
+REM <rabbitmq_nodename> sname of the erlang node to connect to (required)
+
+setlocal
+
+if "%1"=="" goto fail
+
+:: set timeout vars ::
+set TIMEOUT=10
+set TIMER=1
+
+:: check that wmic exists ::
+set WMIC_PATH=%SYSTEMROOT%\System32\Wbem\wmic.exe
+if not exist "%WMIC_PATH%" (
+ goto fail
+)
+
+:getpid
+for /f "usebackq tokens=* skip=1" %%P IN (`%%WMIC_PATH%% process where "name='erl.exe' and commandline like '%%-sname %1%%'" get processid 2^>nul`) do (
+ set PID=%%P
+ goto echopid
+)
+
+:echopid
+:: check for pid not found ::
+if "%PID%" == "" (
+ PING 127.0.0.1 -n 2 > nul
+ set /a TIMER+=1
+ if %TIMEOUT%==%TIMER% goto fail
+ goto getpid
+)
+
+:: show pid ::
+echo %PID%
+
+:: all done ::
+:ok
+endlocal
+EXIT /B 0
+
+:: something went wrong ::
+:fail
+endlocal
+EXIT /B 1
+
+
diff --git a/src/rabbit.erl b/src/rabbit.erl
index 0a0ca90a63..dd5fb89ce4 100644
--- a/src/rabbit.erl
+++ b/src/rabbit.erl
@@ -212,14 +212,13 @@
-type(file_suffix() :: binary()).
%% this really should be an abstract type
-type(log_location() :: 'tty' | 'undefined' | file:filename()).
+-type(param() :: atom()).
-spec(maybe_hipe_compile/0 :: () -> 'ok').
-spec(prepare/0 :: () -> 'ok').
-spec(start/0 :: () -> 'ok').
-spec(stop/0 :: () -> 'ok').
-spec(stop_and_halt/0 :: () -> no_return()).
--spec(rotate_logs/1 :: (file_suffix()) -> rabbit_types:ok_or_error(any())).
--spec(force_event_refresh/0 :: () -> 'ok').
-spec(status/0 ::
() -> [{pid, integer()} |
{running_applications, [{atom(), string(), string()}]} |
@@ -228,12 +227,11 @@
{memory, any()}]).
-spec(is_running/0 :: () -> boolean()).
-spec(is_running/1 :: (node()) -> boolean()).
--spec(environment/0 :: () -> [{atom() | term()}]).
--spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()).
+-spec(environment/0 :: () -> [{param() | term()}]).
+-spec(rotate_logs/1 :: (file_suffix()) -> rabbit_types:ok_or_error(any())).
+-spec(force_event_refresh/0 :: () -> 'ok').
--spec(maybe_insert_default_data/0 :: () -> 'ok').
--spec(boot_delegate/0 :: () -> 'ok').
--spec(recover/0 :: () -> 'ok').
+-spec(log_location/1 :: ('sasl' | 'kernel') -> log_location()).
-spec(start/2 :: ('normal',[]) ->
{'error',
@@ -243,6 +241,10 @@
{'ok',pid()}).
-spec(stop/1 :: (_) -> 'ok').
+-spec(maybe_insert_default_data/0 :: () -> 'ok').
+-spec(boot_delegate/0 :: () -> 'ok').
+-spec(recover/0 :: () -> 'ok').
+
-endif.
%%----------------------------------------------------------------------------
@@ -712,6 +714,6 @@ config_files() ->
case init:get_argument(config) of
{ok, Files} -> [filename:absname(
filename:rootname(File, ".config") ++ ".config") ||
- File <- Files];
+ [File] <- Files];
error -> []
end.
diff --git a/src/rabbit_misc.erl b/src/rabbit_misc.erl
index 6d8bed83b8..dca3bead75 100644
--- a/src/rabbit_misc.erl
+++ b/src/rabbit_misc.erl
@@ -742,13 +742,14 @@ gb_trees_foreach(Fun, Tree) ->
%% [{"-q",true},{"-p","/"}]}
get_options(Defs, As) ->
lists:foldl(fun(Def, {AsIn, RsIn}) ->
- {AsOut, Value} = case Def of
- {flag, Key} ->
- get_flag(Key, AsIn);
- {option, Key, Default} ->
- get_option(Key, Default, AsIn)
- end,
- {AsOut, [{Key, Value} | RsIn]}
+ {K, {AsOut, V}} =
+ case Def of
+ {flag, Key} ->
+ {Key, get_flag(Key, AsIn)};
+ {option, Key, Default} ->
+ {Key, get_option(Key, Default, AsIn)}
+ end,
+ {AsOut, [{K, V} | RsIn]}
end, {As, []}, Defs).
get_option(K, _Default, [K, V | As]) ->
diff --git a/src/rabbit_mnesia.erl b/src/rabbit_mnesia.erl
index 60dd07708f..4d419fd9a9 100644
--- a/src/rabbit_mnesia.erl
+++ b/src/rabbit_mnesia.erl
@@ -732,18 +732,18 @@ reset(Force) ->
false -> ok
end,
Node = node(),
+ Nodes = all_clustered_nodes() -- [Node],
case Force of
true -> ok;
false ->
ensure_mnesia_dir(),
start_mnesia(),
- {Nodes, RunningNodes} =
+ RunningNodes =
try
%% Force=true here so that reset still works when clustered
%% with a node which is down
ok = init_db(read_cluster_nodes_config(), true),
- {all_clustered_nodes() -- [Node],
- running_clustered_nodes() -- [Node]}
+ running_clustered_nodes() -- [Node]
after
stop_mnesia()
end,
@@ -751,6 +751,10 @@ reset(Force) ->
rabbit_misc:ensure_ok(mnesia:delete_schema([Node]),
cannot_delete_schema)
end,
+ %% We need to make sure that we don't end up in a distributed
+ %% Erlang system with nodes while not being in an Mnesia cluster
+ %% with them. We don't handle that well.
+ [erlang:disconnect_node(N) || N <- Nodes],
ok = delete_cluster_nodes_config(),
%% remove persisted messages and any other garbage we find
ok = rabbit_file:recursive_delete(filelib:wildcard(dir() ++ "/*")),
diff --git a/src/rabbit_reader.erl b/src/rabbit_reader.erl
index 908a279c0c..01242e81b8 100644
--- a/src/rabbit_reader.erl
+++ b/src/rabbit_reader.erl
@@ -505,9 +505,11 @@ handle_frame(Type, Channel, Payload,
process_frame(Frame, Channel, State) ->
case get({channel, Channel}) of
{ChPid, AState} ->
- NewAState = process_channel_frame(Frame, Channel, ChPid, AState),
- put({channel, Channel}, {ChPid, NewAState}),
- post_process_frame(Frame, ChPid, State);
+ case process_channel_frame(Frame, ChPid, AState) of
+ {ok, NewAState} -> put({channel, Channel}, {ChPid, NewAState}),
+ post_process_frame(Frame, ChPid, State);
+ {error, Reason} -> handle_exception(State, Channel, Reason)
+ end;
undefined when ?IS_RUNNING(State) ->
ok = create_channel(Channel, State),
process_frame(Frame, Channel, State);
@@ -910,17 +912,15 @@ create_channel(Channel, State) ->
put({channel, Channel}, {ChPid, AState}),
ok.
-process_channel_frame(Frame, Channel, ChPid, AState) ->
+process_channel_frame(Frame, ChPid, AState) ->
case rabbit_command_assembler:process(Frame, AState) of
- {ok, NewAState} -> NewAState;
+ {ok, NewAState} -> {ok, NewAState};
{ok, Method, NewAState} -> rabbit_channel:do(ChPid, Method),
- NewAState;
+ {ok, NewAState};
{ok, Method, Content, NewAState} -> rabbit_channel:do_flow(
ChPid, Method, Content),
- NewAState;
- {error, Reason} -> self() ! {channel_exit, Channel,
- Reason},
- AState
+ {ok, NewAState};
+ {error, Reason} -> {error, Reason}
end.
handle_exception(State = #v1{connection_state = closed}, _Channel, _Reason) ->
diff --git a/src/rabbit_ssl.erl b/src/rabbit_ssl.erl
index 3025d981d4..22ff555ff0 100644
--- a/src/rabbit_ssl.erl
+++ b/src/rabbit_ssl.erl
@@ -21,7 +21,7 @@
-include_lib("public_key/include/public_key.hrl").
-export([peer_cert_issuer/1, peer_cert_subject/1, peer_cert_validity/1]).
--export([peer_cert_subject_items/2]).
+-export([peer_cert_subject_items/2, peer_cert_auth_name/1]).
%%--------------------------------------------------------------------------
@@ -36,6 +36,8 @@
-spec(peer_cert_validity/1 :: (certificate()) -> string()).
-spec(peer_cert_subject_items/2 ::
(certificate(), tuple()) -> [string()] | 'not_found').
+-spec(peer_cert_auth_name/1 ::
+ (certificate()) -> binary() | 'not_found' | 'unsafe').
-endif.
@@ -76,6 +78,43 @@ peer_cert_validity(Cert) ->
format_asn1_value(End)])
end, Cert).
+%% Extract a username from the certificate
+peer_cert_auth_name(Cert) ->
+ {ok, Mode} = application:get_env(rabbit, ssl_cert_login_from),
+ peer_cert_auth_name(Mode, Cert).
+
+peer_cert_auth_name(distinguished_name, Cert) ->
+ case auth_config_sane() of
+ true -> iolist_to_binary(peer_cert_subject(Cert));
+ false -> unsafe
+ end;
+
+peer_cert_auth_name(common_name, Cert) ->
+ %% If there is more than one CN then we join them with "," in a
+ %% vaguely DN-like way. But this is more just so we do something
+ %% more intelligent than crashing, if you actually want to escape
+ %% things properly etc, use DN mode.
+ case auth_config_sane() of
+ true -> case peer_cert_subject_items(Cert, ?'id-at-commonName') of
+ not_found -> not_found;
+ CNs -> list_to_binary(string:join(CNs, ","))
+ end;
+ false -> unsafe
+ end.
+
+auth_config_sane() ->
+ {ok, Opts} = application:get_env(rabbit, ssl_options),
+ case {proplists:get_value(fail_if_no_peer_cert, Opts),
+ proplists:get_value(verify, Opts)} of
+ {true, verify_peer} ->
+ true;
+ {F, V} ->
+ rabbit_log:warning("SSL certificate authentication disabled, "
+ "fail_if_no_peer_cert=~p; "
+ "verify=~p~n", [F, V]),
+ false
+ end.
+
%%--------------------------------------------------------------------------
cert_info(F, Cert) ->
diff --git a/src/rabbit_tests.erl b/src/rabbit_tests.erl
index 165bdbe246..863292144e 100644
--- a/src/rabbit_tests.erl
+++ b/src/rabbit_tests.erl
@@ -71,10 +71,13 @@ maybe_run_cluster_dependent_tests() ->
run_cluster_dependent_tests(SecondaryNode) ->
SecondaryNodeS = atom_to_list(SecondaryNode),
+ cover:stop(SecondaryNode),
ok = control_action(stop_app, []),
ok = control_action(reset, []),
ok = control_action(cluster, [SecondaryNodeS]),
ok = control_action(start_app, []),
+ cover:start(SecondaryNode),
+ ok = control_action(start_app, SecondaryNode, [], []),
io:format("Running cluster dependent tests with node ~p~n", [SecondaryNode]),
passed = test_delegates_async(SecondaryNode),
@@ -960,7 +963,9 @@ test_cluster_management2(SecondaryNode) ->
ok = control_action(cluster, [SecondaryNodeS, NodeS]),
ok = control_action(start_app, []),
ok = control_action(stop_app, []),
+ cover:stop(SecondaryNode),
ok = control_action(reset, []),
+ cover:start(SecondaryNode),
%% attempt to leave cluster when no other node is alive
ok = control_action(cluster, [SecondaryNodeS, NodeS]),
@@ -977,7 +982,15 @@ test_cluster_management2(SecondaryNode) ->
%% leave system clustered, with the secondary node as a ram node
ok = control_action(force_reset, []),
ok = control_action(start_app, []),
- ok = control_action(force_reset, SecondaryNode, [], []),
+ %% Yes, this is rather ugly. But since we're a clustered Mnesia
+ %% node and we're telling another clustered node to reset itself,
+ %% we will get disconnected half way through causing a
+ %% badrpc. This never happens in real life since rabbitmqctl is
+ %% not a clustered Mnesia node.
+ cover:stop(SecondaryNode),
+ {badrpc, nodedown} = control_action(force_reset, SecondaryNode, [], []),
+ pong = net_adm:ping(SecondaryNode),
+ cover:start(SecondaryNode),
ok = control_action(cluster, SecondaryNode, [NodeS], []),
ok = control_action(start_app, SecondaryNode, [], []),