diff --git a/Ganeti/HTools/Cluster.hs b/Ganeti/HTools/Cluster.hs index e7910e9c83cf13316386ed3923fb4820bb72437c..60d4ddd3c9881e92203c2b61dccdab66b63a9152 100644 --- a/Ganeti/HTools/Cluster.hs +++ b/Ganeti/HTools/Cluster.hs @@ -624,19 +624,21 @@ tryAlloc :: (Monad m) => -> Instance.List -- ^ The instance list -> Instance.Instance -- ^ The instance to allocate -> Int -- ^ Required number of nodes - -> m [(Maybe Node.List, [Node.Node])] -- ^ Possible solution list + -> m [(Maybe Node.List, Instance.Instance, [Node.Node])] + -- ^ Possible solution list tryAlloc nl _ inst 2 = let all_nodes = getOnline nl all_pairs = liftM2 (,) all_nodes all_nodes ok_pairs = filter (\(x, y) -> Node.idx x /= Node.idx y) all_pairs - sols = map (\(p, s) -> - (fst $ allocateOnPair nl inst p s, [p, s])) + sols = map (\(p, s) -> let (mnl, i) = allocateOnPair nl inst p s + in (mnl, i, [p, s])) ok_pairs in return sols tryAlloc nl _ inst 1 = let all_nodes = getOnline nl - sols = map (\p -> (fst $ allocateOnSingle nl inst p, [p])) + sols = map (\p -> let (mnl, i) = allocateOnSingle nl inst p + in (mnl, i, [p])) all_nodes in return sols @@ -651,16 +653,17 @@ tryReloc :: (Monad m) => -> Idx -- ^ The index of the instance to move -> Int -- ^ The numver of nodes required -> [Ndx] -- ^ Nodes which should not be used - -> m [(Maybe Node.List, [Node.Node])] -- ^ Solution list + -> m [(Maybe Node.List, Instance.Instance, [Node.Node])] + -- ^ Solution list tryReloc nl il xid 1 ex_idx = let all_nodes = getOnline nl inst = Container.find xid il ex_idx' = (Instance.pnode inst):ex_idx valid_nodes = filter (not . flip elem ex_idx' . Node.idx) all_nodes valid_idxes = map Node.idx valid_nodes - sols1 = map (\x -> let (mnl, _, _, _) = - applyMove nl inst (ReplaceSecondary x) - in (mnl, [Container.find x nl]) + sols1 = map (\x -> let (mnl, i, _, _) = + applyMove nl inst (ReplaceSecondary x) + in (mnl, i, [Container.find x nl]) ) valid_idxes in return sols1 diff --git a/hail.hs b/hail.hs index afc04887e03a3b8d474d130a5ed46ade76dcc611..5c7f71ec0f00347ab14402aa563b099652b47d57 100644 --- a/hail.hs +++ b/hail.hs @@ -44,6 +44,7 @@ import qualified Ganeti.HTools.CLI as CLI import Ganeti.HTools.IAlloc import Ganeti.HTools.Types import Ganeti.HTools.Loader (RqType(..), Request(..)) +import Ganeti.HTools.Utils -- | Command line options structure. data Options = Options @@ -74,15 +75,15 @@ options = ] -filterFails :: (Monad m) => [(Maybe Node.List, [Node.Node])] +filterFails :: (Monad m) => [(Maybe Node.List, Instance.Instance, [Node.Node])] -> m [(Node.List, [Node.Node])] filterFails sols = if null sols then fail "No nodes onto which to allocate at all" - else let sols' = filter (isJust . fst) sols + else let sols' = filter (isJust . fst3) sols in if null sols' then fail "No valid allocation solutions" else - return $ map (\(x, y) -> (fromJust x, y)) sols' + return $ map (\(x, _, y) -> (fromJust x, y)) sols' processResults :: (Monad m) => [(Node.List, [Node.Node])] -> m (String, [Node.Node]) diff --git a/hspace.hs b/hspace.hs index 01aa28036f408eb91d1173d24086d62424a86f79..00d629c1735b0d24cfef3e3f46c343c74affc772 100644 --- a/hspace.hs +++ b/hspace.hs @@ -132,20 +132,20 @@ options = "show help" ] -filterFails :: (Monad m) => [(Maybe Node.List, [Node.Node])] - -> m [(Node.List, [Node.Node])] +filterFails :: (Monad m) => [(Maybe Node.List, Instance.Instance, [Node.Node])] + -> m [(Node.List, Instance.Instance, [Node.Node])] filterFails sols = if null sols then fail "No nodes onto which to allocate at all" - else let sols' = filter (isJust . fst) sols + else let sols' = filter (isJust . fst3) sols in if null sols' then fail "No valid allocation solutions" else - return $ map (\(x, y) -> (fromJust x, y)) sols' + return $ map (\(x, y, z) -> (fromJust x, y, z)) sols' -processResults :: (Monad m) => [(Node.List, [Node.Node])] - -> m (Node.List, [Node.Node]) +processResults :: (Monad m) => [(Node.List, Instance.Instance, [Node.Node])] + -> m (Node.List, Instance.Instance, [Node.Node]) processResults sols = - let sols' = map (\(nl', ns) -> (Cluster.compCV nl', (nl', ns))) sols + let sols' = map (\e@(nl', _, _) -> (Cluster.compCV nl', e)) sols sols'' = sortBy (compare `on` fst) sols' in return $ snd $ head sols'' @@ -153,21 +153,23 @@ iterateDepth :: Node.List -> Instance.List -> Instance.Instance -> Int - -> Int - -> (Node.List, Int) -iterateDepth nl il newinst nreq depth = - let newname = printf "new-%d" depth + -> [Instance.Instance] + -> (Node.List, [Instance.Instance]) +iterateDepth nl il newinst nreq ixes = + let depth = length ixes + newname = printf "new-%d" depth newidx = (length $ Container.elems il) + depth newi2 = Instance.setIdx (Instance.setName newinst newname) newidx sols = Cluster.tryAlloc nl il newi2 nreq - orig = (nl, depth) + orig = (nl, ixes) in if isNothing sols then orig else let sols' = fromJust sols sols'' = filterFails sols' in if isNothing sols'' then orig - else let (xnl, _) = fromJust $ processResults $ fromJust sols'' - in iterateDepth xnl il newinst nreq (depth+1) + else let (xnl, xi, _) = fromJust $ processResults $ + fromJust sols'' + in iterateDepth xnl il newinst nreq (xi:ixes) -- | Main function. @@ -183,6 +185,7 @@ main = do let verbose = optVerbose opts (fixed_nl, il, csf) <- CLI.loadExternalData opts + let num_instances = length $ Container.elems il let offline_names = optOffline opts all_nodes = Container.elems fixed_nl @@ -193,7 +196,7 @@ main = do all_nodes when (length offline_wrong > 0) $ do - printf "Wrong node name(s) set as offline: %s\n" + printf "Error: Wrong node name(s) set as offline: %s\n" (commaJoin offline_wrong) exitWith $ ExitFailure 1 @@ -206,7 +209,7 @@ main = do let bad_nodes = fst $ Cluster.computeBadItems nl il when (length bad_nodes > 0) $ do - putStrLn "Cluster not N+1, no space to allocate." + putStrLn "Error: Cluster not N+1, no space to allocate." exitWith $ ExitFailure 1 when (optShowNodes opts) $ @@ -215,22 +218,42 @@ main = do putStrLn $ Cluster.printNodes nl let ini_cv = Cluster.compCV nl + (orig_mem, orig_disk) = Cluster.totalResources nl (if verbose > 2 then printf "Initial coefficients: overall %.8f, %s\n" ini_cv (Cluster.printStats nl) else printf "Initial score: %.8f\n" ini_cv) + printf "Initial instances: %d\n" num_instances + printf "Initial free RAM: %d\n" orig_mem + printf "Initial free disk: %d\n" orig_disk - let imlen = Container.maxNameLen il - nmlen = Container.maxNameLen nl + let nmlen = Container.maxNameLen nl newinst = Instance.create "new" (optIMem opts) (optIDsk opts) "ADMIN_down" (-1) (-1) - let (fin_nl, fin_depth) = iterateDepth nl il newinst (optINodes opts) 0 - - unless (verbose == 0) $ - printf "Solution length=%d\n" fin_depth + let (fin_nl, ixes) = + iterateDepth nl il newinst (optINodes opts) [] + allocs = length ixes + fin_instances = num_instances + allocs + fin_ixes = reverse ixes + ix_namelen = maximum . map (length . Instance.name) $ fin_ixes + (final_mem, final_disk) = Cluster.totalResources fin_nl + + printf "Final score: %.8f\n" (Cluster.compCV fin_nl) + printf "Final instances: %d\n" (num_instances + allocs) + printf "Final free RAM: %d\n" final_mem + printf "Final free disk: %d\n" final_disk + printf "Usage: %.2f\n" (((fromIntegral num_instances)::Double) / + (fromIntegral fin_instances)) + printf "Allocations: %d\n" allocs + when (verbose > 1) $ do + putStr . unlines . map (\i -> printf "Inst: %*s %-*s %-*s" + ix_namelen (Instance.name i) + nmlen (Container.nameOf fin_nl $ Instance.pnode i) + nmlen (Container.nameOf fin_nl $ Instance.snode i)) + $ fin_ixes when (optShowNodes opts) $ do