X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/53f00b200bee1102bfa3566670629bd729ccc15d..e4c5beaf3ee5cf16fd40573e3afe9a708b58bb4f:/Ganeti/HTools/Cluster.hs diff --git a/Ganeti/HTools/Cluster.hs b/Ganeti/HTools/Cluster.hs index 73c814a..33d523c 100644 --- a/Ganeti/HTools/Cluster.hs +++ b/Ganeti/HTools/Cluster.hs @@ -15,6 +15,7 @@ module Ganeti.HTools.Cluster , Solution(..) , Table(..) , Removal + , Score -- * Generic functions , totalResources -- * First phase functions @@ -31,7 +32,6 @@ module Ganeti.HTools.Cluster , compCV , printStats -- * Loading functions - , loadData , checkData ) where @@ -39,16 +39,14 @@ import Data.List import Data.Maybe (isNothing, fromJust) import Text.Printf (printf) import Data.Function +import Control.Monad import qualified Ganeti.HTools.Container as Container import qualified Ganeti.HTools.Instance as Instance import qualified Ganeti.HTools.Node as Node +import Ganeti.HTools.Types import Ganeti.HTools.Utils -type NodeList = Container.Container Node.Node -type InstanceList = Container.Container Instance.Instance --- | The type used to hold idx-to-name mappings -type NameList = [(Int, String)] -- | A separate name for the cluster score type type Score = Double @@ -202,7 +200,7 @@ those nodes. computeBadItems :: NodeList -> InstanceList -> ([Node.Node], [Instance.Instance]) computeBadItems nl il = - let bad_nodes = verifyN1 $ Container.elems nl + let bad_nodes = verifyN1 $ filter (not . Node.offline) $ Container.elems nl bad_instances = map (\idx -> Container.find idx il) $ sort $ nub $ concat $ map (\ n -> (Node.slist n) ++ (Node.plist n)) bad_nodes @@ -343,11 +341,10 @@ applyMove nl inst Failover = old_s = Container.find old_sdx nl int_p = Node.removePri old_p inst int_s = Node.removeSec old_s inst - new_p = Node.addPri int_s inst - new_s = Node.addSec int_p inst old_sdx - new_nl = if isNothing(new_p) || isNothing(new_s) then Nothing - else Just $ Container.addTwo old_pdx (fromJust new_s) - old_sdx (fromJust new_p) nl + new_nl = do -- Maybe monad + new_p <- Node.addPri int_s inst + new_s <- Node.addSec int_p inst old_sdx + return $ Container.addTwo old_pdx new_s old_sdx new_p nl in (new_nl, Instance.setBoth inst old_sdx old_pdx, old_sdx, old_pdx) -- Replace the primary (f:, r:np, f) @@ -359,12 +356,11 @@ applyMove nl inst (ReplacePrimary new_pdx) = tgt_n = Container.find new_pdx nl int_p = Node.removePri old_p inst int_s = Node.removeSec old_s inst - new_p = Node.addPri tgt_n inst - new_s = Node.addSec int_s inst new_pdx - new_nl = if isNothing(new_p) || isNothing(new_s) then Nothing - else Just $ Container.add new_pdx (fromJust new_p) $ - Container.addTwo old_pdx int_p - old_sdx (fromJust new_s) nl + new_nl = do -- Maybe monad + new_p <- Node.addPri tgt_n inst + new_s <- Node.addSec int_s inst new_pdx + return $ Container.add new_pdx new_p $ + Container.addTwo old_pdx int_p old_sdx new_s nl in (new_nl, Instance.setPri inst new_pdx, new_pdx, old_sdx) -- Replace the secondary (r:ns) @@ -374,10 +370,9 @@ applyMove nl inst (ReplaceSecondary new_sdx) = old_s = Container.find old_sdx nl tgt_n = Container.find new_sdx nl int_s = Node.removeSec old_s inst - new_s = Node.addSec tgt_n inst old_pdx - new_nl = if isNothing(new_s) then Nothing - else Just $ Container.addTwo new_sdx (fromJust new_s) - old_sdx int_s nl + new_nl = Node.addSec tgt_n inst old_pdx >>= + \new_s -> return $ Container.addTwo new_sdx + new_s old_sdx int_s nl in (new_nl, Instance.setSec inst new_sdx, old_pdx, new_sdx) -- Replace the secondary and failover (r:np, f) @@ -389,12 +384,11 @@ applyMove nl inst (ReplaceAndFailover new_pdx) = tgt_n = Container.find new_pdx nl int_p = Node.removePri old_p inst int_s = Node.removeSec old_s inst - new_p = Node.addPri tgt_n inst - new_s = Node.addSec int_p inst new_pdx - new_nl = if isNothing(new_p) || isNothing(new_s) then Nothing - else Just $ Container.add new_pdx (fromJust new_p) $ - Container.addTwo old_pdx (fromJust new_s) - old_sdx int_s nl + new_nl = do -- Maybe monad + new_p <- Node.addPri tgt_n inst + new_s <- Node.addSec int_p inst new_pdx + return $ Container.add new_pdx new_p $ + Container.addTwo old_pdx new_s old_sdx int_s nl in (new_nl, Instance.setBoth inst new_pdx old_pdx, new_pdx, old_pdx) -- Failver and replace the secondary (f, r:ns) @@ -406,12 +400,11 @@ applyMove nl inst (FailoverAndReplace new_sdx) = tgt_n = Container.find new_sdx nl int_p = Node.removePri old_p inst int_s = Node.removeSec old_s inst - new_p = Node.addPri int_s inst - new_s = Node.addSec tgt_n inst old_sdx - new_nl = if isNothing(new_p) || isNothing(new_s) then Nothing - else Just $ Container.add new_sdx (fromJust new_s) $ - Container.addTwo old_sdx (fromJust new_p) - old_pdx int_p nl + new_nl = do -- Maybe monad + new_p <- Node.addPri int_s inst + new_s <- Node.addSec tgt_n inst old_sdx + return $ Container.add new_sdx new_s $ + Container.addTwo old_sdx new_p old_pdx int_p nl in (new_nl, Instance.setBoth inst old_sdx new_sdx, old_sdx, new_sdx) checkSingleStep :: Table -- ^ The original table @@ -478,8 +471,10 @@ checkMove nodes_idx ini_tbl victims = -- iterate over all instances, computing the best move best_tbl = foldl' - (\ step_tbl elem -> compareTables step_tbl $ - checkInstanceMove nodes_idx ini_tbl elem) + (\ step_tbl elem -> + if Instance.snode elem == Node.noSecondary then step_tbl + else compareTables step_tbl $ + checkInstanceMove nodes_idx ini_tbl elem) ini_tbl victims Table _ _ _ best_plc = best_tbl in @@ -563,27 +558,27 @@ computeMoves i a b c d = else if c == b then {- Failover and ... -} if d == a then {- that's all -} - ("f", [printf "migrate %s" i]) + ("f", [printf "migrate -f %s" i]) else (printf "f r:%s" d, - [printf "migrate %s" i, + [printf "migrate -f %s" i, printf "replace-disks -n %s %s" d i]) else if d == a then {- ... and keep primary as secondary -} (printf "r:%s f" c, [printf "replace-disks -n %s %s" c i, - printf "migrate %s" i]) + printf "migrate -f %s" i]) else if d == b then {- ... keep same secondary -} (printf "f r:%s f" c, - [printf "migrate %s" i, + [printf "migrate -f %s" i, printf "replace-disks -n %s %s" c i, - printf "migrate %s" i]) + printf "migrate -f %s" i]) else {- Nothing in common -} (printf "r:%s f r:%s" c d, [printf "replace-disks -n %s %s" c i, - printf "migrate %s" i, + printf "migrate -f %s" i, printf "replace-disks -n %s %s" d i]) {-| Converts a placement to string format -} @@ -616,9 +611,11 @@ printSolutionLine il ktn kti nmlen imlen plc pos = formatCmds :: [[String]] -> String formatCmds cmd_strs = - unlines $ map (" echo " ++) $ + unlines $ concat $ map (\(a, b) -> - (printf "step %d" (a::Int)):(map ("gnt-instance " ++) b)) $ + (printf "echo step %d" (a::Int)): + (printf "check"): + (map ("gnt-instance " ++) b)) $ zip [1..] cmd_strs {-| Converts a solution to string format -} @@ -689,98 +686,6 @@ printStats nl = -- Loading functions -{- | Convert newline and delimiter-separated text. - -This function converts a text in tabular format as generated by -@gnt-instance list@ and @gnt-node list@ to a list of objects using a -supplied conversion function. - --} -loadTabular :: String -> ([String] -> (String, a)) - -> (a -> Int -> a) -> ([(String, Int)], [(Int, a)]) -loadTabular text_data convert_fn set_fn = - let lines_data = lines text_data - rows = map (sepSplit '|') lines_data - kerows = (map convert_fn rows) - idxrows = map (\ (idx, (k, v)) -> ((k, idx), (idx, set_fn v idx))) - (zip [0..] kerows) - in unzip idxrows - --- | For each instance, add its index to its primary and secondary nodes -fixNodes :: [(Int, Node.Node)] - -> [(Int, Instance.Instance)] - -> [(Int, Node.Node)] -fixNodes nl il = - foldl' (\accu (idx, inst) -> - let - assocEqual = (\ (i, _) (j, _) -> i == j) - pdx = Instance.pnode inst - sdx = Instance.snode inst - pold = fromJust $ lookup pdx accu - sold = fromJust $ lookup sdx accu - pnew = Node.setPri pold idx - snew = Node.setSec sold idx - ac1 = deleteBy assocEqual (pdx, pold) accu - ac2 = deleteBy assocEqual (sdx, sold) ac1 - ac3 = (pdx, pnew):(sdx, snew):ac2 - in ac3) nl il - --- | Compute the longest common suffix of a NameList list that --- | starts with a dot -longestDomain :: NameList -> String -longestDomain [] = "" -longestDomain ((_,x):xs) = - let - onlyStrings = snd $ unzip xs - in - foldr (\ suffix accu -> if all (isSuffixOf suffix) onlyStrings - then suffix - else accu) - "" $ filter (isPrefixOf ".") (tails x) - --- | Remove tails from the (Int, String) lists -stripSuffix :: String -> NameList -> NameList -stripSuffix suffix lst = - let sflen = length suffix in - map (\ (key, name) -> (key, take ((length name) - sflen) name)) lst - -{-| Initializer function that loads the data from a node and list file - and massages it into the correct format. -} -loadData :: String -- ^ Node data in text format - -> String -- ^ Instance data in text format - -> (Container.Container Node.Node, - Container.Container Instance.Instance, - String, NameList, NameList) -loadData ndata idata = - let - {- node file: name t_mem n_mem f_mem t_disk f_disk -} - (ktn, nl) = loadTabular ndata - (\ (name:tm:nm:fm:td:fd:[]) -> - (name, - Node.create (read tm) (read nm) - (read fm) (read td) (read fd))) - Node.setIdx - {- instance file: name mem disk status pnode snode -} - (kti, il) = loadTabular idata - (\ (name:mem:dsk:status:pnode:snode:[]) -> - (name, - Instance.create (read mem) (read dsk) - status - (fromJust $ lookup pnode ktn) - (fromJust $ lookup snode ktn))) - Instance.setIdx - nl2 = fixNodes nl il - il3 = Container.fromAssocList il - nl3 = Container.fromAssocList - (map (\ (k, v) -> (k, Node.buildPeers v il3 (length nl2))) nl2) - xtn = swapPairs ktn - xti = swapPairs kti - common_suffix = longestDomain (xti ++ xtn) - stn = stripSuffix common_suffix xtn - sti = stripSuffix common_suffix xti - in - (nl3, il3, common_suffix, stn, sti) - -- | Compute the amount of memory used by primary instances on a node. nodeImem :: Node.Node -> InstanceList -> Int nodeImem node il = @@ -788,6 +693,13 @@ nodeImem node il = in sum . map Instance.mem . map rfind $ Node.plist node +-- | Compute the amount of disk used by instances on a node (either primary +-- or secondary). +nodeIdsk :: Node.Node -> InstanceList -> Int +nodeIdsk node il = + let rfind = flip Container.find $ il + in sum . map Instance.dsk . + map rfind $ (Node.plist node) ++ (Node.slist node) -- | Check cluster data for consistency checkData :: NodeList -> InstanceList -> NameList -> NameList @@ -804,12 +716,15 @@ checkData nl il ktn _ = - (Node.f_mem node) - (nodeImem node il) + adj_mem + delta_dsk = (truncate $ Node.t_dsk node) + - (Node.f_dsk node) + - (nodeIdsk node il) newn = Node.setFmem (Node.setXmem node delta_mem) (Node.f_mem node - adj_mem) - umsg = if delta_mem > 16 - then (printf "node %s has %6d MB of unaccounted \ - \memory " - nname delta_mem):msgs - else msgs - in (umsg, newn) + umsg1 = if delta_mem > 512 || delta_dsk > 1024 + then [printf "node %s is missing %d MB ram \ + \and %d GB disk" + nname delta_mem (delta_dsk `div` 1024)] + else [] + in (msgs ++ umsg1, newn) ) [] nl