Revision 97da6b71 htools/Ganeti/HTools/Cluster.hs
b/htools/Ganeti/HTools/Cluster.hs | ||
---|---|---|
922 | 922 |
ops = iMoveToJob nl' il' idx (ReplaceSecondary ndx) |
923 | 923 |
return (nl', il', ops) |
924 | 924 |
|
925 |
-- The algorithm for ChangeAll is as follows: |
|
926 |
-- |
|
927 |
-- * generate all (primary, secondary) node pairs for the target groups |
|
928 |
-- * for each pair, execute the needed moves (r:s, f, r:s) and compute |
|
929 |
-- the final node list state and group score |
|
930 |
-- * select the best choice via a foldl that uses the same Either |
|
931 |
-- String solution as the ChangeSecondary mode |
|
925 | 932 |
nodeEvacInstance nl il ChangeAll |
926 | 933 |
inst@(Instance.Instance {Instance.diskTemplate = DTDrbd8}) |
927 | 934 |
gdx avail_nodes = |
928 | 935 |
do |
929 |
let primary = Container.find (Instance.pNode inst) nl |
|
930 |
idx = Instance.idx inst |
|
931 |
no_nodes = Left "no nodes available" |
|
932 |
-- if the primary is offline, then we first failover |
|
933 |
(nl1, inst1, ops1) <- |
|
934 |
if Node.offline primary |
|
935 |
then do |
|
936 |
(nl', inst', _, _) <- |
|
937 |
annotateResult "Failing over to the secondary" $ |
|
938 |
opToResult $ applyMove nl inst Failover |
|
939 |
return (nl', inst', [Failover]) |
|
940 |
else return (nl, inst, []) |
|
941 |
-- we now need to execute a replace secondary to the future |
|
942 |
-- primary node |
|
943 |
(nl2, inst2, _, new_pdx) <- annotateResult "Searching for a new primary" $ |
|
944 |
eitherToResult $ |
|
945 |
foldl' (evacDrbdSecondaryInner nl1 inst1 gdx) |
|
946 |
no_nodes avail_nodes |
|
947 |
let ops2 = ReplaceSecondary new_pdx:ops1 |
|
948 |
-- since we chose the new primary, we remove it from the list of |
|
949 |
-- available nodes |
|
950 |
let avail_nodes_sec = new_pdx `delete` avail_nodes |
|
951 |
-- we now execute another failover, the primary stays fixed now |
|
952 |
(nl3, inst3, _, _) <- annotateResult "Failing over to new primary" $ |
|
953 |
opToResult $ applyMove nl2 inst2 Failover |
|
954 |
let ops3 = Failover:ops2 |
|
955 |
-- and finally another replace secondary, to the final secondary |
|
956 |
(nl4, inst4, _, new_sdx) <- |
|
957 |
annotateResult "Searching for a new secondary" $ |
|
936 |
let no_nodes = Left "no nodes available" |
|
937 |
node_pairs = [(p,s) | p <- avail_nodes, s <- avail_nodes, p /= s] |
|
938 |
(nl', il', ops, _) <- |
|
939 |
annotateResult "Can't find any good nodes for relocation" $ |
|
958 | 940 |
eitherToResult $ |
959 |
foldl' (evacDrbdSecondaryInner nl3 inst3 gdx) no_nodes avail_nodes_sec |
|
960 |
let ops4 = ReplaceSecondary new_sdx:ops3 |
|
961 |
il' = Container.add idx inst4 il |
|
962 |
ops = concatMap (iMoveToJob nl4 il' idx) $ reverse ops4 |
|
963 |
return (nl4, il', ops) |
|
941 |
foldl' |
|
942 |
(\accu nodes -> case evacDrbdAllInner nl il inst gdx nodes of |
|
943 |
Bad msg -> |
|
944 |
case accu of |
|
945 |
Right _ -> accu |
|
946 |
-- we don't need more details (which |
|
947 |
-- nodes, etc.) as we only selected |
|
948 |
-- this group if we can allocate on |
|
949 |
-- it, hence failures will not |
|
950 |
-- propagate out of this fold loop |
|
951 |
Left _ -> Left $ "Allocation failed: " ++ msg |
|
952 |
Ok result@(_, _, _, new_cv) -> |
|
953 |
let new_accu = Right result in |
|
954 |
case accu of |
|
955 |
Left _ -> new_accu |
|
956 |
Right (_, _, _, old_cv) -> |
|
957 |
if old_cv < new_cv |
|
958 |
then accu |
|
959 |
else new_accu |
|
960 |
) no_nodes node_pairs |
|
961 |
|
|
962 |
return (nl', il', ops) |
|
964 | 963 |
|
965 | 964 |
-- | Inner fold function for changing secondary of a DRBD instance. |
966 | 965 |
-- |
967 |
-- The "running" solution is either a @Left String@, which means we
|
|
966 |
-- The running solution is either a @Left String@, which means we
|
|
968 | 967 |
-- don't have yet a working solution, or a @Right (...)@, which |
969 | 968 |
-- represents a valid solution; it holds the modified node list, the |
970 | 969 |
-- modified instance (after evacuation), the score of that solution, |
... | ... | |
1003 | 1002 |
then accu |
1004 | 1003 |
else new_accu |
1005 | 1004 |
|
1005 |
-- | Compute result of changing all nodes of a DRBD instance. |
|
1006 |
-- |
|
1007 |
-- Given the target primary and secondary node (which might be in a |
|
1008 |
-- different group or not), this function will 'execute' all the |
|
1009 |
-- required steps and assuming all operations succceed, will return |
|
1010 |
-- the modified node and instance lists, the opcodes needed for this |
|
1011 |
-- and the new group score. |
|
1012 |
evacDrbdAllInner :: Node.List -- ^ Cluster node list |
|
1013 |
-> Instance.List -- ^ Cluster instance list |
|
1014 |
-> Instance.Instance -- ^ The instance to be moved |
|
1015 |
-> Gdx -- ^ The target group index |
|
1016 |
-- (which can differ from the |
|
1017 |
-- current group of the |
|
1018 |
-- instance) |
|
1019 |
-> (Ndx, Ndx) -- ^ Tuple of new |
|
1020 |
-- primary\/secondary nodes |
|
1021 |
-> Result (Node.List, Instance.List, [OpCodes.OpCode], Score) |
|
1022 |
evacDrbdAllInner nl il inst gdx (t_pdx, t_sdx) = |
|
1023 |
do |
|
1024 |
let primary = Container.find (Instance.pNode inst) nl |
|
1025 |
idx = Instance.idx inst |
|
1026 |
-- if the primary is offline, then we first failover |
|
1027 |
(nl1, inst1, ops1) <- |
|
1028 |
if Node.offline primary |
|
1029 |
then do |
|
1030 |
(nl', inst', _, _) <- |
|
1031 |
annotateResult "Failing over to the secondary" $ |
|
1032 |
opToResult $ applyMove nl inst Failover |
|
1033 |
return (nl', inst', [Failover]) |
|
1034 |
else return (nl, inst, []) |
|
1035 |
let (o1, o2, o3) = (ReplaceSecondary t_pdx, |
|
1036 |
Failover, |
|
1037 |
ReplaceSecondary t_sdx) |
|
1038 |
-- we now need to execute a replace secondary to the future |
|
1039 |
-- primary node |
|
1040 |
(nl2, inst2, _, _) <- |
|
1041 |
annotateResult "Changing secondary to new primary" $ |
|
1042 |
opToResult $ |
|
1043 |
applyMove nl1 inst1 o1 |
|
1044 |
let ops2 = o1:ops1 |
|
1045 |
-- we now execute another failover, the primary stays fixed now |
|
1046 |
(nl3, inst3, _, _) <- annotateResult "Failing over to new primary" $ |
|
1047 |
opToResult $ applyMove nl2 inst2 o2 |
|
1048 |
let ops3 = o2:ops2 |
|
1049 |
-- and finally another replace secondary, to the final secondary |
|
1050 |
(nl4, inst4, _, _) <- |
|
1051 |
annotateResult "Changing secondary to final secondary" $ |
|
1052 |
opToResult $ |
|
1053 |
applyMove nl3 inst3 o3 |
|
1054 |
let ops4 = o3:ops3 |
|
1055 |
il' = Container.add idx inst4 il |
|
1056 |
ops = concatMap (iMoveToJob nl4 il' idx) $ reverse ops4 |
|
1057 |
let nodes = Container.elems nl4 |
|
1058 |
-- The fromJust below is ugly (it can fail nastily), but |
|
1059 |
-- at this point we should have any internal mismatches, |
|
1060 |
-- and adding a monad here would be quite involved |
|
1061 |
grpnodes = fromJust (gdx `lookup` Node.computeGroups nodes) |
|
1062 |
new_cv = compCVNodes grpnodes |
|
1063 |
return (nl4, il', ops, new_cv) |
|
1064 |
|
|
1006 | 1065 |
-- | Computes the nodes in a given group which are available for |
1007 | 1066 |
-- allocation. |
1008 | 1067 |
availableGroupNodes :: [(Gdx, [Ndx])] -- ^ Group index/node index assoc list |
Also available in: Unified diff