diff options
| -rw-r--r-- | Makefile | 6 | ||||
| -rw-r--r-- | docs/rabbitmq-echopid.xml | 71 | ||||
| -rw-r--r-- | docs/rabbitmqctl.1.xml | 7 | ||||
| -rw-r--r-- | ebin/rabbit_app.in | 1 | ||||
| -rw-r--r-- | packaging/macports/Portfile.in | 9 | ||||
| -rw-r--r-- | packaging/windows/Makefile | 3 | ||||
| -rw-r--r-- | scripts/rabbitmq-echopid.bat | 49 | ||||
| -rw-r--r-- | src/rabbit.erl | 18 | ||||
| -rw-r--r-- | src/rabbit_misc.erl | 15 | ||||
| -rw-r--r-- | src/rabbit_mnesia.erl | 10 | ||||
| -rw-r--r-- | src/rabbit_reader.erl | 20 | ||||
| -rw-r--r-- | src/rabbit_ssl.erl | 41 | ||||
| -rw-r--r-- | src/rabbit_tests.erl | 15 |
13 files changed, 226 insertions, 39 deletions
@@ -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 <<ulink url="mailto:info@rabbitmq.com"><email>info@rabbitmq.com</email></ulink>></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, [], []), |
