65 |
65 |
, tryEvac
|
66 |
66 |
, tryMGEvac
|
67 |
67 |
, tryNodeEvac
|
|
68 |
, tryChangeGroup
|
68 |
69 |
, collapseFailures
|
69 |
70 |
-- * Allocation functions
|
70 |
71 |
, iterateAlloc
|
... | ... | |
906 |
907 |
failOnSecondaryChange _ _ = return ()
|
907 |
908 |
|
908 |
909 |
-- | Run evacuation for a single instance.
|
|
910 |
--
|
|
911 |
-- /Note:/ this function should correctly execute both intra-group
|
|
912 |
-- evacuations (in all modes) and inter-group evacuations (in the
|
|
913 |
-- 'ChangeAll' mode). Of course, this requires that the correct list
|
|
914 |
-- of target nodes is passed.
|
909 |
915 |
nodeEvacInstance :: Node.List -- ^ The node list (cluster-wide)
|
910 |
916 |
-> Instance.List -- ^ Instance list (cluster-wide)
|
911 |
917 |
-> EvacMode -- ^ The evacuation mode
|
... | ... | |
1091 |
1097 |
(map (`Container.find` ini_il) idxs)
|
1092 |
1098 |
in return $ reverseEvacSolution esol
|
1093 |
1099 |
|
|
1100 |
-- | Change-group IAllocator mode main function.
|
|
1101 |
--
|
|
1102 |
-- This is very similar to 'tryNodeEvac', the only difference is that
|
|
1103 |
-- we don't choose as target group the current instance group, but
|
|
1104 |
-- instead:
|
|
1105 |
--
|
|
1106 |
-- 1. at the start of the function, we compute which are the target
|
|
1107 |
-- groups; either no groups were passed in, in which case we choose
|
|
1108 |
-- all groups out of which we don't evacuate instance, or there were
|
|
1109 |
-- some groups passed, in which case we use those
|
|
1110 |
--
|
|
1111 |
-- 2. for each instance, we use 'findBestAllocGroup' to choose the
|
|
1112 |
-- best group to hold the instance, and then we do what
|
|
1113 |
-- 'tryNodeEvac' does, except for this group instead of the current
|
|
1114 |
-- instance group.
|
|
1115 |
--
|
|
1116 |
-- Note that the correct behaviour of this function relies on the
|
|
1117 |
-- function 'nodeEvacInstance' to be able to do correctly both
|
|
1118 |
-- intra-group and inter-group moves when passed the 'ChangeAll' mode.
|
|
1119 |
tryChangeGroup :: Group.List -- ^ The cluster groups
|
|
1120 |
-> Node.List -- ^ The node list (cluster-wide)
|
|
1121 |
-> Instance.List -- ^ Instance list (cluster-wide)
|
|
1122 |
-> [Gdx] -- ^ Target groups; if empty, any
|
|
1123 |
-- groups not being evacuated
|
|
1124 |
-> [Idx] -- ^ List of instance (indices) to be evacuated
|
|
1125 |
-> Result EvacSolution
|
|
1126 |
tryChangeGroup gl ini_nl ini_il gdxs idxs =
|
|
1127 |
let evac_gdxs = nub $ map (instancePriGroup ini_nl .
|
|
1128 |
flip Container.find ini_il) idxs
|
|
1129 |
target_gdxs = (if null gdxs
|
|
1130 |
then Container.keys gl
|
|
1131 |
else gdxs) \\ evac_gdxs
|
|
1132 |
offline = map Node.idx . filter Node.offline $ Container.elems ini_nl
|
|
1133 |
excl_ndx = foldl' (flip IntSet.insert) IntSet.empty offline
|
|
1134 |
group_ndx = map (\(gdx, (nl, _)) -> (gdx, map Node.idx
|
|
1135 |
(Container.elems nl))) $
|
|
1136 |
splitCluster ini_nl ini_il
|
|
1137 |
(_, _, esol) =
|
|
1138 |
foldl' (\state@(nl, il, _) inst ->
|
|
1139 |
let solution = do
|
|
1140 |
let ncnt = Instance.requiredNodes $
|
|
1141 |
Instance.diskTemplate inst
|
|
1142 |
(gdx, _, _) <- findBestAllocGroup gl nl il
|
|
1143 |
(Just target_gdxs) inst ncnt
|
|
1144 |
av_nodes <- availableGroupNodes group_ndx
|
|
1145 |
excl_ndx gdx
|
|
1146 |
nodeEvacInstance nl il ChangeAll inst av_nodes
|
|
1147 |
in updateEvacSolution state inst solution
|
|
1148 |
)
|
|
1149 |
(ini_nl, ini_il, emptyEvacSolution)
|
|
1150 |
(map (`Container.find` ini_il) idxs)
|
|
1151 |
in return $ reverseEvacSolution esol
|
|
1152 |
|
|
1153 |
|
1094 |
1154 |
-- | Recursively place instances on the cluster until we're out of space.
|
1095 |
1155 |
iterateAlloc :: Node.List
|
1096 |
1156 |
-> Instance.List
|