summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/rabbitmq-diagnostics.827
-rw-r--r--src/rabbit_amqqueue.erl11
-rw-r--r--src/rabbit_feature_flags.erl79
-rw-r--r--test/quorum_queue_SUITE.erl2
4 files changed, 108 insertions, 11 deletions
diff --git a/docs/rabbitmq-diagnostics.8 b/docs/rabbitmq-diagnostics.8
index 754506c1bd..6c9b636c3c 100644
--- a/docs/rabbitmq-diagnostics.8
+++ b/docs/rabbitmq-diagnostics.8
@@ -231,6 +231,14 @@ Example:
.Sp
.Dl rabbitmq-diagnostics alarms
.\" ------------------------------------
+.It Cm certificates
+.Pp
+Displays the node certificates for every listener on target node that is configured to use TLS.
+.Pp
+Example:
+.sp
+.Dl rabbitmq-diagnostics certificates
+.\" ------------------------------------
.It Cm check_alarms
.Pp
Health check that fails (returns with a non-zero code) if there are alarms
@@ -244,6 +252,25 @@ Example:
.Sp
.Dl rabbitmq-diagnostics check_alarms
.\" ------------------------------------
+.It Cm check_certificate_expiration Oo Fl -unit Ar time_unit Oc Op Fl -within Ar seconds
+.Pp
+Checks the expiration date on the certificates for every listener on target node that is configured to use TLS.
+Supported time units are:
+.Bl -bullet
+.It
+days
+.It
+weeks
+.It
+months
+.It
+years
+.El
+.Pp
+Example:
+.Sp
+.Dl rabbitmq-diagnostics check_certificate_expiration --unit weeks --within 6
+.\" ------------------------------------
.It Cm check_local_alarms
.Pp
Health check that fails (returns with a non-zero code) if there are alarms
diff --git a/src/rabbit_amqqueue.erl b/src/rabbit_amqqueue.erl
index c7099a07b1..ff83bc9d04 100644
--- a/src/rabbit_amqqueue.erl
+++ b/src/rabbit_amqqueue.erl
@@ -309,9 +309,14 @@ do_declare(Q, _Node) when ?amqqueue_is_quorum(Q) ->
declare_classic_queue(Q, Node) ->
QName = amqqueue:get_name(Q),
VHost = amqqueue:get_vhost(Q),
- Node1 = case rabbit_queue_master_location_misc:get_location(Q) of
- {ok, Node0} -> Node0;
- {error, _} -> Node
+ Node1 = case Node of
+ {ignore_location, Node0} ->
+ Node0;
+ _ ->
+ case rabbit_queue_master_location_misc:get_location(Q) of
+ {ok, Node0} -> Node0;
+ {error, _} -> Node
+ end
end,
Node1 = rabbit_mirror_queue_misc:initial_queue_node(Q, Node1),
case rabbit_vhost_sup_sup:get_vhost_sup(VHost, Node1) of
diff --git a/src/rabbit_feature_flags.erl b/src/rabbit_feature_flags.erl
index 71c719a1b6..9440c6cd0b 100644
--- a/src/rabbit_feature_flags.erl
+++ b/src/rabbit_feature_flags.erl
@@ -246,6 +246,8 @@
migration_fun/0,
migration_fun_context/0]).
+-on_load(on_load/0).
+
-spec list() -> feature_flags().
%% @doc
%% Lists all supported feature flags.
@@ -1639,8 +1641,9 @@ does_node_support(Node, FeatureNames, Timeout) ->
end,
case Ret of
{error, pre_feature_flags_rabbitmq} ->
- %% See run_feature_flags_mod_on_remote_node/4 for an
- %% explanation why we consider this node a 3.7.x node.
+ %% See run_feature_flags_mod_on_remote_node/4 for
+ %% an explanation why we consider this node a 3.7.x
+ %% pre-feature-flags node.
rabbit_log:debug(
"Feature flags: no feature flags support on node `~s`, "
"consider the feature flags unsupported: ~p",
@@ -1803,8 +1806,9 @@ run_feature_flags_mod_on_remote_node(Node, Function, Args, Timeout) ->
{undef,
[{?MODULE, Function, Args, []}
| _]}}} ->
- %% If rabbit_feature_flags:is_supported_locally/1 is undefined
- %% on the remote node, we consider it to be a 3.7.x node.
+ %% If rabbit_feature_flags:Function() is undefined
+ %% on the remote node, we consider it to be a 3.7.x
+ %% pre-feature-flags node.
%%
%% Theoretically, it could be an older version (3.6.x and
%% older). But the RabbitMQ version consistency check
@@ -1813,7 +1817,7 @@ run_feature_flags_mod_on_remote_node(Node, Function, Args, Timeout) ->
%% this situation from happening before we reach this point.
rabbit_log:debug(
"Feature flags: ~s:~s~p unavailable on node `~s`: "
- "assuming it is a RabbitMQ 3.7.x node",
+ "assuming it is a RabbitMQ 3.7.x pre-feature-flags node",
[?MODULE, Function, Args, Node]),
{error, pre_feature_flags_rabbitmq};
{badrpc, Reason} = Error ->
@@ -1838,8 +1842,9 @@ query_remote_feature_flags(Node, Which, Timeout) ->
[Which, Node]),
case run_feature_flags_mod_on_remote_node(Node, list, [Which], Timeout) of
{error, pre_feature_flags_rabbitmq} ->
- %% See run_feature_flags_mod_on_remote_node/4 for an
- %% explanation why we consider this node a 3.7.x node.
+ %% See run_feature_flags_mod_on_remote_node/4 for
+ %% an explanation why we consider this node a 3.7.x
+ %% pre-feature-flags node.
rabbit_log:debug(
"Feature flags: no feature flags support on node `~s`, "
"consider the list of feature flags empty", [Node]),
@@ -2262,3 +2267,63 @@ maybe_enable_locally_after_app_load([FeatureName | Rest]) ->
share_new_feature_flags_after_app_load(FeatureFlags, Timeout) ->
push_local_feature_flags_from_apps_unknown_remotely(
node(), FeatureFlags, Timeout).
+
+on_load() ->
+ %% The goal of this `on_load()` code server hook is to prevent this
+ %% module from being loaded in an already running RabbitMQ node if
+ %% the running version does not have the feature flags subsystem.
+ %%
+ %% This situation happens when an upgrade overwrites RabbitMQ files
+ %% with the node still running. This is the case with many packages:
+ %% files are updated on disk, then a post-install step takes care of
+ %% restarting the service.
+ %%
+ %% The problem is that if many nodes in a cluster are updated at the
+ %% same time, one node running the newer version might query feature
+ %% flags on an old node where this module is already available
+ %% (because files were already overwritten). This causes the query
+ %% to report an unexpected answer and the newer node to refuse to
+ %% start.
+ %%
+ %% However, when the module is executed outside of RabbitMQ (for
+ %% debugging purpose or in the context of EUnit for instance), we
+ %% want to allow the load. That's why we first check if RabbitMQ is
+ %% actually running.
+ case rabbit:is_running() of
+ true ->
+ %% RabbitMQ is running.
+ %%
+ %% Now we want to differenciate a pre-feature-flags node
+ %% from one having the subsystem.
+ %%
+ %% To do that, we verify if the `feature_flags_file`
+ %% application environment variable is defined. With a
+ %% feature-flags-enabled node, this application environment
+ %% variable is defined by rabbitmq-server(8).
+ case application:get_env(rabbit, feature_flags_file) of
+ {ok, _} ->
+ %% This is a feature-flags-enabled version. Loading
+ %% the module is permitted.
+ ok;
+ _ ->
+ %% This is a pre-feature-flags version. We deny the
+ %% load and report why, possibly specifying the
+ %% version of RabbitMQ.
+ Vsn = case application:get_key(rabbit, vsn) of
+ {ok, V} -> V;
+ undefined -> "unknown version"
+ end,
+ "Refusing to load '" ?MODULE_STRING "' on this "
+ "node. It appears to be running a pre-feature-flags "
+ "version of RabbitMQ (" ++ Vsn ++ "). This is fine: "
+ "a newer version of RabbitMQ was deployed on this "
+ "node, but it was not restarted yet. This warning "
+ "is probably caused by a remote node querying this "
+ "node for its feature flags."
+ end;
+ false ->
+ %% RabbitMQ is not running. Loading the module is permitted
+ %% because this Erlang node will never be queried for its
+ %% feature flags.
+ ok
+ end.
diff --git a/test/quorum_queue_SUITE.erl b/test/quorum_queue_SUITE.erl
index 384e7a818e..bed7dedae0 100644
--- a/test/quorum_queue_SUITE.erl
+++ b/test/quorum_queue_SUITE.erl
@@ -1197,7 +1197,7 @@ simple_confirm_availability_on_leader_change(Config) ->
publish_confirm(Ch, QQ),
%% stop the node hosting the leader
- stop_node(Config, Node2),
+ ok = rabbit_ct_broker_helpers:stop_node(Config, Node2),
%% this should not fail as the channel should detect the new leader and
%% resend to that
publish_confirm(Ch, QQ),