1%% This Source Code Form is subject to the terms of the Mozilla Public 2%% License, v. 2.0. If a copy of the MPL was not distributed with this 3%% file, You can obtain one at https://mozilla.org/MPL/2.0/. 4%% 5%% Copyright (c) 2010-2021 VMware, Inc. or its affiliates. All rights reserved. 6%% 7 8-module(rabbit_mirror_queue_mode_nodes). 9 10-include_lib("rabbit_common/include/rabbit.hrl"). 11 12-behaviour(rabbit_mirror_queue_mode). 13 14-export([description/0, suggested_queue_nodes/5, validate_policy/1]). 15 16-rabbit_boot_step({?MODULE, 17 [{description, "mirror mode nodes"}, 18 {mfa, {rabbit_registry, register, 19 [ha_mode, <<"nodes">>, ?MODULE]}}, 20 {requires, rabbit_registry}, 21 {enables, kernel_ready}]}). 22 23description() -> 24 [{description, <<"Mirror queue to specified nodes">>}]. 25 26suggested_queue_nodes(PolicyNodes0, CurrentMaster, _SNodes, SSNodes, NodesRunningRabbitMQ) -> 27 PolicyNodes1 = [list_to_atom(binary_to_list(Node)) || Node <- PolicyNodes0], 28 %% If the current master is not in the nodes specified, then what we want 29 %% to do depends on whether there are any synchronised mirrors. If there 30 %% are then we can just kill the current master - the admin has asked for 31 %% a migration and we should give it to them. If there are not however 32 %% then we must keep the master around so as not to lose messages. 33 34 PolicyNodes = case SSNodes of 35 [] -> lists:usort([CurrentMaster | PolicyNodes1]); 36 _ -> PolicyNodes1 37 end, 38 Unavailable = PolicyNodes -- NodesRunningRabbitMQ, 39 AvailablePolicyNodes = PolicyNodes -- Unavailable, 40 case AvailablePolicyNodes of 41 [] -> %% We have never heard of anything? Not much we can do but 42 %% keep the master alive. 43 {CurrentMaster, []}; 44 _ -> case lists:member(CurrentMaster, AvailablePolicyNodes) of 45 true -> {CurrentMaster, 46 AvailablePolicyNodes -- [CurrentMaster]}; 47 false -> %% Make sure the new master is synced! In order to 48 %% get here SSNodes must not be empty. 49 SyncPolicyNodes = [Node || 50 Node <- AvailablePolicyNodes, 51 lists:member(Node, SSNodes)], 52 NewMaster = case SyncPolicyNodes of 53 [Node | _] -> Node; 54 [] -> erlang:hd(SSNodes) 55 end, 56 {NewMaster, AvailablePolicyNodes -- [NewMaster]} 57 end 58 end. 59 60validate_policy([]) -> 61 {error, "ha-mode=\"nodes\" list must be non-empty", []}; 62validate_policy(Nodes) when is_list(Nodes) -> 63 case [I || I <- Nodes, not is_binary(I)] of 64 [] -> ok; 65 Invalid -> {error, "ha-mode=\"nodes\" takes a list of strings, " 66 "~p was not a string", [Invalid]} 67 end; 68validate_policy(Params) -> 69 {error, "ha-mode=\"nodes\" takes a list, ~p given", [Params]}. 70