From 9dcec0011685db5521ecdeb6ed8af93b4a93a3dd Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Mon, 1 Jun 2009 15:48:44 +0200 Subject: [PATCH] Rework the tryAlloc/tryReloc functions Currently tryAlloc/tryReloc do not return the new instance, as this is not needed for IAllocator alloc/reloc requests. However, for computing the space, the new instance is useful, so we modify these functions to return this information too. The patch also improves hspace to have (with default parameters) a parseable output. --- Ganeti/HTools/Cluster.hs | 19 +++++++----- hail.hs | 7 +++-- hspace.hs | 67 +++++++++++++++++++++++++++------------- 3 files changed, 60 insertions(+), 33 deletions(-) diff --git a/Ganeti/HTools/Cluster.hs b/Ganeti/HTools/Cluster.hs index e7910e9c8..60d4ddd3c 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 afc04887e..5c7f71ec0 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 01aa28036..00d629c17 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 -- GitLab