X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/e4f08c462e8469337c87331db617c37e00c474c4..8b42a5dbedfdd33ad8614687c75ec110f3c384f3:/src/hbal.hs diff --git a/src/hbal.hs b/src/hbal.hs index c5089db..7b98d19 100644 --- a/src/hbal.hs +++ b/src/hbal.hs @@ -16,14 +16,19 @@ import Text.Printf (printf) import qualified Container import qualified Cluster +import qualified Version +import Rapi +import Utils -- | Command line options structure. data Options = Options { optShowNodes :: Bool , optShowCmds :: Bool + , optOneline :: Bool , optNodef :: FilePath , optInstf :: FilePath , optMaxRounds :: Int + , optMaster :: String } deriving Show -- | Default values for the command line options. @@ -31,30 +36,34 @@ defaultOptions :: Options defaultOptions = Options { optShowNodes = False , optShowCmds = False + , optOneline = False , optNodef = "nodes" , optInstf = "instances" , optMaxRounds = -1 + , optMaster = "" } {- | Start computing the solution at the given depth and recurse until we find a valid solution or we exceed the maximum depth. -} -iterateDepth :: Cluster.Table - -> Int -- ^ Current round - -> Int -- ^ Max rounds - -> IO Cluster.Table -iterateDepth ini_tbl cur_round max_rounds = - let Cluster.Table _ ini_il ini_cv ini_plc = ini_tbl +iterateDepth :: Cluster.Table -- The starting table + -> Int -- ^ Current round + -> Int -- ^ Max rounds + -> Bool -- ^ Wheter to be silent + -> IO Cluster.Table -- The resulting table +iterateDepth ini_tbl cur_round max_rounds oneline = + let Cluster.Table ini_nl ini_il ini_cv ini_plc = ini_tbl all_inst = Container.elems ini_il - fin_tbl = Cluster.checkMove ini_tbl all_inst + node_idx = Container.keys ini_nl + fin_tbl = Cluster.checkMove node_idx ini_tbl all_inst (Cluster.Table _ _ fin_cv fin_plc) = fin_tbl ini_plc_len = length ini_plc fin_plc_len = length fin_plc allowed_next = (max_rounds < 0 || cur_round < max_rounds) in do - printf " - round %d: " cur_round + unless oneline $ printf " - round %d: " cur_round hFlush stdout let msg = if fin_cv < ini_cv then @@ -67,11 +76,12 @@ iterateDepth ini_tbl cur_round max_rounds = (fin_plc_len - ini_plc_len) else "no improvement, stopping\n" - putStr msg - hFlush stdout + unless oneline $ do + putStr msg + hFlush stdout (if fin_cv < ini_cv then -- this round made success, try deeper if allowed_next - then iterateDepth fin_tbl (cur_round + 1) max_rounds + then iterateDepth fin_tbl (cur_round + 1) max_rounds oneline -- don't go deeper, but return the better solution else return fin_tbl else @@ -86,12 +96,18 @@ options = , Option ['C'] ["print-commands"] (NoArg (\ opts -> opts { optShowCmds = True })) "print the ganeti command list for reaching the solution" + , Option ['o'] ["oneline"] + (NoArg (\ opts -> opts { optOneline = True })) + "print the ganeti command list for reaching the solution" , Option ['n'] ["nodes"] (ReqArg (\ f opts -> opts { optNodef = f }) "FILE") "the node list FILE" , Option ['i'] ["instances"] (ReqArg (\ f opts -> opts { optInstf = f }) "FILE") "the instance list FILE" + , Option ['m'] ["master"] + (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS") + "collect data via RAPI at the given ADDRESS" , Option ['r'] ["max-rounds"] (ReqArg (\ i opts -> opts { optMaxRounds = (read i)::Int }) "N") "do not run for more than R rounds(useful for very unbalanced clusters)" @@ -105,26 +121,40 @@ parseOpts argv = return (foldl (flip id) defaultOptions o, n) (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options)) - where header = "Usage: hbal [OPTION...]" + where header = printf "hbal %s\nUsage: hbal [OPTION...]" + Version.version -- | Main function. main :: IO () main = do cmd_args <- System.getArgs (opts, _) <- parseOpts cmd_args - (nl, il, ktn, kti) <- liftM2 Cluster.loadData - (readFile $ optNodef opts) - (readFile $ optInstf opts) - printf "Loaded %d nodes, %d instances\n" + + let oneline = optOneline opts + let (node_data, inst_data) = + case optMaster opts of + "" -> (readFile $ optNodef opts, + readFile $ optInstf opts) + host -> (readData getNodes host, + readData getInstances host) + + (nl, il, csf, ktn, kti) <- liftM2 Cluster.loadData node_data inst_data + + unless oneline $ printf "Loaded %d nodes, %d instances\n" (Container.size nl) (Container.size il) + + when (length csf > 0 && not oneline) $ do + printf "Note: Stripping common suffix of '%s' from names\n" csf + let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il - printf "Initial check done: %d bad nodes, %d bad instances.\n" + unless oneline $ printf + "Initial check done: %d bad nodes, %d bad instances.\n" (length bad_nodes) (length bad_instances) when (length bad_nodes > 0) $ do - putStrLn "Cluster is not N+1 happy, please fix N+1 first. Exiting." - exitWith $ ExitFailure 1 + putStrLn "Cluster is not N+1 happy, continuing but no guarantee \ + \that the cluster will end N+1 happy." when (optShowNodes opts) $ do @@ -133,21 +163,21 @@ main = do let ini_cv = Cluster.compCV nl ini_tbl = Cluster.Table nl il ini_cv [] - printf "Initial coefficients: overall %.8f, %s\n" - ini_cv (Cluster.printStats nl) + unless oneline $ printf "Initial coefficients: overall %.8f, %s\n" + ini_cv (Cluster.printStats nl) - putStrLn "Trying to minimize the CV..." - fin_tbl <- iterateDepth ini_tbl 1 (optMaxRounds opts) + unless oneline $ putStrLn "Trying to minimize the CV..." + fin_tbl <- iterateDepth ini_tbl 1 (optMaxRounds opts) oneline let (Cluster.Table fin_nl _ fin_cv fin_plc) = fin_tbl ord_plc = reverse fin_plc - printf "Final coefficients: overall %.8f, %s\n" + unless oneline $ printf "Final coefficients: overall %.8f, %s\n" fin_cv (Cluster.printStats fin_nl) - printf "Solution length=%d\n" (length ord_plc) + unless oneline $ printf "Solution length=%d\n" (length ord_plc) let (sol_strs, cmd_strs) = Cluster.printSolution il ktn kti ord_plc - putStr $ unlines $ sol_strs + unless oneline $ putStr $ unlines $ sol_strs when (optShowCmds opts) $ do putStrLn "" @@ -162,3 +192,6 @@ main = do putStrLn $ Cluster.printNodes ktn fin_nl printf "Original: mem=%d disk=%d\n" orig_mem orig_disk printf "Final: mem=%d disk=%d\n" final_mem final_disk + when oneline $ do + printf "%.8f %d %.8f %8.3f\n" + ini_cv (length ord_plc) fin_cv (ini_cv / fin_cv)