@@ -215,19 +215,19 @@ setup_steps() ->
215215 fun rabbit_ct_helpers :ensure_rabbitmqctl_app /1 ,
216216 fun rabbit_ct_helpers :ensure_rabbitmq_plugins_cmd /1 ,
217217 fun set_lager_flood_limit /1 ,
218+ fun configure_metadata_store /1 ,
218219 fun start_rabbitmq_nodes /1 ,
219- fun share_dist_and_proxy_ports_map /1 ,
220- fun configure_metadata_store /1
220+ fun share_dist_and_proxy_ports_map /1
221221 ];
222222 _ ->
223223 [
224224 fun rabbit_ct_helpers :ensure_rabbitmqctl_cmd /1 ,
225225 fun rabbit_ct_helpers :load_rabbitmqctl_app /1 ,
226226 fun rabbit_ct_helpers :ensure_rabbitmq_plugins_cmd /1 ,
227227 fun set_lager_flood_limit /1 ,
228+ fun configure_metadata_store /1 ,
228229 fun start_rabbitmq_nodes /1 ,
229- fun share_dist_and_proxy_ports_map /1 ,
230- fun configure_metadata_store /1
230+ fun share_dist_and_proxy_ports_map /1
231231 ]
232232 end .
233233
@@ -441,8 +441,24 @@ start_rabbitmq_node(Master, Config, NodeConfig, I) ->
441441 {failed_boot_attempts , Attempts + 1 }),
442442 start_rabbitmq_node (Master , Config , NodeConfig5 , I );
443443 NodeConfig4 ->
444- Master ! {self (), I , NodeConfig4 },
445- unlink (Master )
444+ case uses_expected_metadata_store (Config , NodeConfig4 ) of
445+ {MetadataStore , MetadataStore } ->
446+ Master ! {self (), I , NodeConfig4 },
447+ unlink (Master );
448+ {ExpectedMetadataStore , UsedMetadataStore } ->
449+ % % If the active metadata store is not the one expected, we
450+ % % stop the node and skip the test.
451+ _ = stop_rabbitmq_node (Config , NodeConfig4 ),
452+ Nodename = ? config (nodename , NodeConfig4 ),
453+ Error = {skip ,
454+ rabbit_misc :format (
455+ " Node ~s is using the ~s metadata store, "
456+ " ~s was expected" ,
457+ [Nodename , UsedMetadataStore ,
458+ ExpectedMetadataStore ])},
459+ Master ! {self (), Error },
460+ unlink (Master )
461+ end
446462 end .
447463
448464run_node_steps (Config , NodeConfig , I , [Step | Rest ]) ->
@@ -883,6 +899,67 @@ query_node(Config, NodeConfig) ->
883899 cover_add_node (Nodename ),
884900 rabbit_ct_helpers :set_config (NodeConfig , Vars ).
885901
902+ uses_expected_metadata_store (Config , NodeConfig ) ->
903+ % % We want to verify if the active metadata store matches the expected one.
904+ % %
905+ % % Before that, we may need to enable `khepri_db' on the node because if it
906+ % % doesn't support the relative forced feature flags mechanism, it will
907+ % % ignore the setting from `configure_metadata_store/1'. In this case, we
908+ % % have to enable it at runtime.
909+ Nodename = ? config (nodename , NodeConfig ),
910+ ExpectedMetadataStore = rabbit_ct_helpers :get_config (
911+ Config , metadata_store ),
912+ case ExpectedMetadataStore of
913+ mnesia -> ok ;
914+ khepri -> maybe_enable_khepri_as_expected (Config , Nodename )
915+ end ,
916+ IsKhepriEnabled = rpc (Config , Nodename , rabbit_khepri , is_enabled , []),
917+ UsedMetadataStore = case IsKhepriEnabled of
918+ true -> khepri ;
919+ false -> mnesia
920+ end ,
921+ ct :pal (
922+ " Metadata store on ~s : expected=~s , used=~s " ,
923+ [Nodename , UsedMetadataStore , ExpectedMetadataStore ]),
924+ {ExpectedMetadataStore , UsedMetadataStore }.
925+
926+ maybe_enable_khepri_as_expected (Config , Nodename ) ->
927+ % % We detect if the remote node supports the relative forced feature flags
928+ % % mechanism by checking if `rabbit_feature_flags:get_require_level/1' is
929+ % % exported. This is unrelated to the mechanism but it was committed around
930+ % % the same time and was not backported either.
931+ RelativeForcedFeatureFlagsUnsupported = (
932+ rpc (Config , Nodename ,
933+ erlang , function_exported ,
934+ [rabbit_feature_flags , get_require_level , 1 ])
935+ ),
936+ case RelativeForcedFeatureFlagsUnsupported of
937+ true ->
938+ ok ;
939+ false ->
940+ ct :pal (
941+ " Relative forced feature flags unsupported on ~s , "
942+ " enable Khepri now to enable expected metadata store" ,
943+ [Nodename ]),
944+ Ret = enable_feature_flag (Config , [Nodename ], khepri_db ),
945+ case Ret of
946+ ok ->
947+ ok ;
948+ {error , missing_clustered_nodes } ->
949+ ct :pal (
950+ " Tried to enable Khepri on ~s as expected, but node "
951+ " not ready; retrying in 1 second" ,
952+ [Nodename ]),
953+ timer :sleep (1000 ),
954+ maybe_enable_khepri_as_expected (Config , Nodename );
955+ _ ->
956+ ct :pal (
957+ " Tried to enable Khepri on ~s as expected: ~0p " ,
958+ [Nodename , Ret ]),
959+ ok
960+ end
961+ end .
962+
886963maybe_cluster_nodes (Config ) ->
887964 Clustered0 = rabbit_ct_helpers :get_config (Config , rmq_nodes_clustered ),
888965 Clustered = case Clustered0 of
@@ -999,57 +1076,71 @@ share_dist_and_proxy_ports_map(Config) ->
9991076configured_metadata_store (Config ) ->
10001077 case rabbit_ct_helpers :get_config (Config , metadata_store ) of
10011078 khepri ->
1002- {khepri , []};
1003- {khepri , _FFs0 } = Khepri ->
1004- Khepri ;
1079+ khepri ;
10051080 mnesia ->
10061081 mnesia ;
10071082 _ ->
10081083 case os :getenv (" RABBITMQ_METADATA_STORE" ) of
1009- " khepri" ->
1010- {khepri , []};
1011- _ ->
1012- mnesia
1084+ " khepri" -> khepri ;
1085+ _ -> mnesia
10131086 end
10141087 end .
10151088
10161089configure_metadata_store (Config ) ->
10171090 ct :log (" Configuring metadata store..." ),
1018- case configured_metadata_store (Config ) of
1019- {khepri , FFs0 } ->
1020- case enable_khepri_metadata_store (Config , FFs0 ) of
1021- {skip , _ } = Skip ->
1022- _ = stop_rabbitmq_nodes (Config ),
1023- Skip ;
1024- Config1 ->
1025- Config1
1091+ Value = rabbit_ct_helpers :get_app_env (
1092+ Config , rabbit , forced_feature_flags_on_init , undefined ),
1093+ MetadataStore = configured_metadata_store (Config ),
1094+ Config1 = rabbit_ct_helpers :set_config (
1095+ Config , {metadata_store , MetadataStore }),
1096+ % % To enabled or disable `khepri_db', we use the relative forced feature
1097+ % % flags mechanism. This allows us to select the state of Khepri without
1098+ % % having to worry about other feature flags.
1099+ % %
1100+ % % However, RabbitMQ 4.0.x and older don't support it. See the
1101+ % % `uses_expected_metadata_store/2' check to see how Khepri is enabled in
1102+ % % this case.
1103+ case MetadataStore of
1104+ khepri ->
1105+ ct :log (" Enabling Khepri metadata store" ),
1106+ case Value of
1107+ undefined ->
1108+ rabbit_ct_helpers :merge_app_env (
1109+ Config1 ,
1110+ {rabbit ,
1111+ [{forced_feature_flags_on_init ,
1112+ {rel , [khepri_db ], []}}]});
1113+ _ ->
1114+ rabbit_ct_helpers :merge_app_env (
1115+ Config1 ,
1116+ {rabbit ,
1117+ [{forced_feature_flags_on_init ,
1118+ [khepri_db | Value ]}]})
10261119 end ;
10271120 mnesia ->
10281121 ct :log (" Enabling Mnesia metadata store" ),
1029- Config
1122+ case Value of
1123+ undefined ->
1124+ rabbit_ct_helpers :merge_app_env (
1125+ Config1 ,
1126+ {rabbit ,
1127+ [{forced_feature_flags_on_init ,
1128+ {rel , [], [khepri_db ]}}]});
1129+ _ ->
1130+ rabbit_ct_helpers :merge_app_env (
1131+ Config1 ,
1132+ {rabbit ,
1133+ [{forced_feature_flags_on_init ,
1134+ Value -- [khepri_db ]}]})
1135+ end
10301136 end .
10311137
1032- enable_khepri_metadata_store (Config , FFs0 ) ->
1033- ct :log (" Enabling Khepri metadata store" ),
1034- FFs = [khepri_db | FFs0 ],
1035- lists :foldl (fun (_FF , {skip , _Reason } = Skip ) ->
1036- Skip ;
1037- (FF , C ) ->
1038- case enable_feature_flag (C , FF ) of
1039- ok ->
1040- C ;
1041- {skip , _ } = Skip ->
1042- ct :pal (" Enabling metadata store failed: ~p " , [Skip ]),
1043- Skip
1044- end
1045- end , Config , FFs ).
1046-
10471138% % Waits until the metadata store replica on Node is up to date with the leader.
10481139await_metadata_store_consistent (Config , Node ) ->
10491140 case configured_metadata_store (Config ) of
10501141 mnesia ->
10511142 ok ;
1052- { khepri , _ } ->
1143+ khepri ->
10531144 RaClusterName = rabbit_khepri :get_ra_cluster_name (),
10541145 Leader = rpc (Config , Node , ra_leaderboard , lookup_leader , [RaClusterName ]),
10551146 LastAppliedLeader = ra_last_applied (Leader ),
0 commit comments