diff options
| -rw-r--r-- | docs/rabbitmq-diagnostics.8 | 27 | ||||
| -rw-r--r-- | src/rabbit_amqqueue.erl | 11 | ||||
| -rw-r--r-- | src/rabbit_feature_flags.erl | 79 | ||||
| -rw-r--r-- | test/quorum_queue_SUITE.erl | 2 |
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), |
