Revision 9dcec001
b/Ganeti/HTools/Cluster.hs | ||
---|---|---|
624 | 624 |
-> Instance.List -- ^ The instance list |
625 | 625 |
-> Instance.Instance -- ^ The instance to allocate |
626 | 626 |
-> Int -- ^ Required number of nodes |
627 |
-> m [(Maybe Node.List, [Node.Node])] -- ^ Possible solution list |
|
627 |
-> m [(Maybe Node.List, Instance.Instance, [Node.Node])] |
|
628 |
-- ^ Possible solution list |
|
628 | 629 |
tryAlloc nl _ inst 2 = |
629 | 630 |
let all_nodes = getOnline nl |
630 | 631 |
all_pairs = liftM2 (,) all_nodes all_nodes |
631 | 632 |
ok_pairs = filter (\(x, y) -> Node.idx x /= Node.idx y) all_pairs |
632 |
sols = map (\(p, s) -> |
|
633 |
(fst $ allocateOnPair nl inst p s, [p, s]))
|
|
633 |
sols = map (\(p, s) -> let (mnl, i) = allocateOnPair nl inst p s
|
|
634 |
in (mnl, i, [p, s]))
|
|
634 | 635 |
ok_pairs |
635 | 636 |
in return sols |
636 | 637 |
|
637 | 638 |
tryAlloc nl _ inst 1 = |
638 | 639 |
let all_nodes = getOnline nl |
639 |
sols = map (\p -> (fst $ allocateOnSingle nl inst p, [p])) |
|
640 |
sols = map (\p -> let (mnl, i) = allocateOnSingle nl inst p |
|
641 |
in (mnl, i, [p])) |
|
640 | 642 |
all_nodes |
641 | 643 |
in return sols |
642 | 644 |
|
... | ... | |
651 | 653 |
-> Idx -- ^ The index of the instance to move |
652 | 654 |
-> Int -- ^ The numver of nodes required |
653 | 655 |
-> [Ndx] -- ^ Nodes which should not be used |
654 |
-> m [(Maybe Node.List, [Node.Node])] -- ^ Solution list |
|
656 |
-> m [(Maybe Node.List, Instance.Instance, [Node.Node])] |
|
657 |
-- ^ Solution list |
|
655 | 658 |
tryReloc nl il xid 1 ex_idx = |
656 | 659 |
let all_nodes = getOnline nl |
657 | 660 |
inst = Container.find xid il |
658 | 661 |
ex_idx' = (Instance.pnode inst):ex_idx |
659 | 662 |
valid_nodes = filter (not . flip elem ex_idx' . Node.idx) all_nodes |
660 | 663 |
valid_idxes = map Node.idx valid_nodes |
661 |
sols1 = map (\x -> let (mnl, _, _, _) =
|
|
662 |
applyMove nl inst (ReplaceSecondary x)
|
|
663 |
in (mnl, [Container.find x nl]) |
|
664 |
sols1 = map (\x -> let (mnl, i, _, _) =
|
|
665 |
applyMove nl inst (ReplaceSecondary x) |
|
666 |
in (mnl, i, [Container.find x nl])
|
|
664 | 667 |
) valid_idxes |
665 | 668 |
in return sols1 |
666 | 669 |
|
b/hail.hs | ||
---|---|---|
44 | 44 |
import Ganeti.HTools.IAlloc |
45 | 45 |
import Ganeti.HTools.Types |
46 | 46 |
import Ganeti.HTools.Loader (RqType(..), Request(..)) |
47 |
import Ganeti.HTools.Utils |
|
47 | 48 |
|
48 | 49 |
-- | Command line options structure. |
49 | 50 |
data Options = Options |
... | ... | |
74 | 75 |
] |
75 | 76 |
|
76 | 77 |
|
77 |
filterFails :: (Monad m) => [(Maybe Node.List, [Node.Node])] |
|
78 |
filterFails :: (Monad m) => [(Maybe Node.List, Instance.Instance, [Node.Node])]
|
|
78 | 79 |
-> m [(Node.List, [Node.Node])] |
79 | 80 |
filterFails sols = |
80 | 81 |
if null sols then fail "No nodes onto which to allocate at all" |
81 |
else let sols' = filter (isJust . fst) sols |
|
82 |
else let sols' = filter (isJust . fst3) sols
|
|
82 | 83 |
in if null sols' then |
83 | 84 |
fail "No valid allocation solutions" |
84 | 85 |
else |
85 |
return $ map (\(x, y) -> (fromJust x, y)) sols' |
|
86 |
return $ map (\(x, _, y) -> (fromJust x, y)) sols'
|
|
86 | 87 |
|
87 | 88 |
processResults :: (Monad m) => [(Node.List, [Node.Node])] |
88 | 89 |
-> m (String, [Node.Node]) |
b/hspace.hs | ||
---|---|---|
132 | 132 |
"show help" |
133 | 133 |
] |
134 | 134 |
|
135 |
filterFails :: (Monad m) => [(Maybe Node.List, [Node.Node])] |
|
136 |
-> m [(Node.List, [Node.Node])] |
|
135 |
filterFails :: (Monad m) => [(Maybe Node.List, Instance.Instance, [Node.Node])]
|
|
136 |
-> m [(Node.List, Instance.Instance, [Node.Node])]
|
|
137 | 137 |
filterFails sols = |
138 | 138 |
if null sols then fail "No nodes onto which to allocate at all" |
139 |
else let sols' = filter (isJust . fst) sols |
|
139 |
else let sols' = filter (isJust . fst3) sols
|
|
140 | 140 |
in if null sols' then |
141 | 141 |
fail "No valid allocation solutions" |
142 | 142 |
else |
143 |
return $ map (\(x, y) -> (fromJust x, y)) sols'
|
|
143 |
return $ map (\(x, y, z) -> (fromJust x, y, z)) sols'
|
|
144 | 144 |
|
145 |
processResults :: (Monad m) => [(Node.List, [Node.Node])] |
|
146 |
-> m (Node.List, [Node.Node]) |
|
145 |
processResults :: (Monad m) => [(Node.List, Instance.Instance, [Node.Node])]
|
|
146 |
-> m (Node.List, Instance.Instance, [Node.Node])
|
|
147 | 147 |
processResults sols = |
148 |
let sols' = map (\(nl', ns) -> (Cluster.compCV nl', (nl', ns))) sols
|
|
148 |
let sols' = map (\e@(nl', _, _) -> (Cluster.compCV nl', e)) sols
|
|
149 | 149 |
sols'' = sortBy (compare `on` fst) sols' |
150 | 150 |
in return $ snd $ head sols'' |
151 | 151 |
|
... | ... | |
153 | 153 |
-> Instance.List |
154 | 154 |
-> Instance.Instance |
155 | 155 |
-> Int |
156 |
-> Int |
|
157 |
-> (Node.List, Int) |
|
158 |
iterateDepth nl il newinst nreq depth = |
|
159 |
let newname = printf "new-%d" depth |
|
156 |
-> [Instance.Instance] |
|
157 |
-> (Node.List, [Instance.Instance]) |
|
158 |
iterateDepth nl il newinst nreq ixes = |
|
159 |
let depth = length ixes |
|
160 |
newname = printf "new-%d" depth |
|
160 | 161 |
newidx = (length $ Container.elems il) + depth |
161 | 162 |
newi2 = Instance.setIdx (Instance.setName newinst newname) newidx |
162 | 163 |
sols = Cluster.tryAlloc nl il newi2 nreq |
163 |
orig = (nl, depth)
|
|
164 |
orig = (nl, ixes)
|
|
164 | 165 |
in |
165 | 166 |
if isNothing sols then orig |
166 | 167 |
else let sols' = fromJust sols |
167 | 168 |
sols'' = filterFails sols' |
168 | 169 |
in if isNothing sols'' then orig |
169 |
else let (xnl, _) = fromJust $ processResults $ fromJust sols'' |
|
170 |
in iterateDepth xnl il newinst nreq (depth+1) |
|
170 |
else let (xnl, xi, _) = fromJust $ processResults $ |
|
171 |
fromJust sols'' |
|
172 |
in iterateDepth xnl il newinst nreq (xi:ixes) |
|
171 | 173 |
|
172 | 174 |
|
173 | 175 |
-- | Main function. |
... | ... | |
183 | 185 |
let verbose = optVerbose opts |
184 | 186 |
|
185 | 187 |
(fixed_nl, il, csf) <- CLI.loadExternalData opts |
188 |
let num_instances = length $ Container.elems il |
|
186 | 189 |
|
187 | 190 |
let offline_names = optOffline opts |
188 | 191 |
all_nodes = Container.elems fixed_nl |
... | ... | |
193 | 196 |
all_nodes |
194 | 197 |
|
195 | 198 |
when (length offline_wrong > 0) $ do |
196 |
printf "Wrong node name(s) set as offline: %s\n" |
|
199 |
printf "Error: Wrong node name(s) set as offline: %s\n"
|
|
197 | 200 |
(commaJoin offline_wrong) |
198 | 201 |
exitWith $ ExitFailure 1 |
199 | 202 |
|
... | ... | |
206 | 209 |
|
207 | 210 |
let bad_nodes = fst $ Cluster.computeBadItems nl il |
208 | 211 |
when (length bad_nodes > 0) $ do |
209 |
putStrLn "Cluster not N+1, no space to allocate." |
|
212 |
putStrLn "Error: Cluster not N+1, no space to allocate."
|
|
210 | 213 |
exitWith $ ExitFailure 1 |
211 | 214 |
|
212 | 215 |
when (optShowNodes opts) $ |
... | ... | |
215 | 218 |
putStrLn $ Cluster.printNodes nl |
216 | 219 |
|
217 | 220 |
let ini_cv = Cluster.compCV nl |
221 |
(orig_mem, orig_disk) = Cluster.totalResources nl |
|
218 | 222 |
|
219 | 223 |
(if verbose > 2 then |
220 | 224 |
printf "Initial coefficients: overall %.8f, %s\n" |
221 | 225 |
ini_cv (Cluster.printStats nl) |
222 | 226 |
else |
223 | 227 |
printf "Initial score: %.8f\n" ini_cv) |
228 |
printf "Initial instances: %d\n" num_instances |
|
229 |
printf "Initial free RAM: %d\n" orig_mem |
|
230 |
printf "Initial free disk: %d\n" orig_disk |
|
224 | 231 |
|
225 |
let imlen = Container.maxNameLen il |
|
226 |
nmlen = Container.maxNameLen nl |
|
232 |
let nmlen = Container.maxNameLen nl |
|
227 | 233 |
newinst = Instance.create "new" (optIMem opts) (optIDsk opts) |
228 | 234 |
"ADMIN_down" (-1) (-1) |
229 | 235 |
|
230 |
let (fin_nl, fin_depth) = iterateDepth nl il newinst (optINodes opts) 0 |
|
231 |
|
|
232 |
unless (verbose == 0) $ |
|
233 |
printf "Solution length=%d\n" fin_depth |
|
236 |
let (fin_nl, ixes) = |
|
237 |
iterateDepth nl il newinst (optINodes opts) [] |
|
238 |
allocs = length ixes |
|
239 |
fin_instances = num_instances + allocs |
|
240 |
fin_ixes = reverse ixes |
|
241 |
ix_namelen = maximum . map (length . Instance.name) $ fin_ixes |
|
242 |
(final_mem, final_disk) = Cluster.totalResources fin_nl |
|
243 |
|
|
244 |
printf "Final score: %.8f\n" (Cluster.compCV fin_nl) |
|
245 |
printf "Final instances: %d\n" (num_instances + allocs) |
|
246 |
printf "Final free RAM: %d\n" final_mem |
|
247 |
printf "Final free disk: %d\n" final_disk |
|
248 |
printf "Usage: %.2f\n" (((fromIntegral num_instances)::Double) / |
|
249 |
(fromIntegral fin_instances)) |
|
250 |
printf "Allocations: %d\n" allocs |
|
251 |
when (verbose > 1) $ do |
|
252 |
putStr . unlines . map (\i -> printf "Inst: %*s %-*s %-*s" |
|
253 |
ix_namelen (Instance.name i) |
|
254 |
nmlen (Container.nameOf fin_nl $ Instance.pnode i) |
|
255 |
nmlen (Container.nameOf fin_nl $ Instance.snode i)) |
|
256 |
$ fin_ixes |
|
234 | 257 |
|
235 | 258 |
when (optShowNodes opts) $ |
236 | 259 |
do |
Also available in: Unified diff