-options :: [OptDescr (Options -> Options)]
-options =
- [ Option ['p'] ["print-nodes"]
- (NoArg (\ opts -> opts { optShowNodes = True }))
- "print the final node list"
- , Option ['C'] ["print-commands"]
- (OptArg ((\ f opts -> opts { optShowCmds = Just f }) . fromMaybe "-")
- "FILE")
- "print the ganeti command list for reaching the solution,\
- \if an argument is passed then write the commands to a file named\
- \ as such"
- , 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, optNodeSet = True }) "FILE")
- "the node list FILE"
- , Option ['i'] ["instances"]
- (ReqArg (\ f opts -> opts { optInstf = f, optInstSet = True }) "FILE")
- "the instance list FILE"
- , Option ['m'] ["master"]
- (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS")
- "collect data via RAPI at the given ADDRESS"
- , Option ['l'] ["max-length"]
- (ReqArg (\ i opts -> opts { optMaxLength = (read i)::Int }) "N")
- "cap the solution at this many moves (useful for very unbalanced \
- \clusters)"
- , Option ['v'] ["verbose"]
- (NoArg (\ opts -> opts { optVerbose = (optVerbose opts) + 1 }))
- "increase the verbosity level"
- , Option ['q'] ["quiet"]
- (NoArg (\ opts -> opts { optVerbose = (optVerbose opts) - 1 }))
- "decrease the verbosity level"
- , Option ['O'] ["offline"]
- (ReqArg (\ n opts -> opts { optOffline = n:optOffline opts }) "NODE")
- " set node as offline"
- , Option ['e'] ["min-score"]
- (ReqArg (\ e opts -> opts { optMinScore = read e }) "EPSILON")
- " mininum score to aim for"
- , Option ['V'] ["version"]
- (NoArg (\ opts -> opts { optShowVer = True}))
- "show the version of the program"
- , Option ['h'] ["help"]
- (NoArg (\ opts -> opts { optShowHelp = True}))
- "show help"
- ]
-
-{- | 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 -- ^ The starting table
- -> Int -- ^ Remaining length
- -> Cluster.NameList -- ^ Node idx to name list
- -> Cluster.NameList -- ^ Inst idx to name list
- -> Int -- ^ Max node name len
- -> Int -- ^ Max instance name len
- -> [[String]] -- ^ Current command list
- -> Bool -- ^ Wheter to be silent
- -> Cluster.Score -- ^ Score at which to stop
- -> IO (Cluster.Table, [[String]]) -- ^ The resulting table and
- -- commands
-iterateDepth ini_tbl max_rounds ktn kti nmlen imlen
- cmd_strs oneline min_score =
- let Cluster.Table ini_nl ini_il ini_cv ini_plc = ini_tbl
- all_inst = Container.elems ini_il
- node_idx = map Node.idx . filter (not . Node.offline) $
- Container.elems 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 || length fin_plc < max_rounds)
- in
- do
- let
- (sol_line, cmds) = Cluster.printSolutionLine ini_il ktn kti
- nmlen imlen (head fin_plc) fin_plc_len
- upd_cmd_strs = cmds:cmd_strs
- unless (oneline || fin_plc_len == ini_plc_len) $ do
- putStrLn sol_line
- hFlush stdout
- (if fin_cv < ini_cv then -- this round made success, try deeper
- if allowed_next && fin_cv > min_score
- then iterateDepth fin_tbl max_rounds ktn kti
- nmlen imlen upd_cmd_strs oneline min_score
- -- don't go deeper, but return the better solution
- else return (fin_tbl, upd_cmd_strs)
- else
- return (ini_tbl, cmd_strs))
-
--- | Formats the solution for the oneline display
-formatOneline :: Double -> Int -> Double -> String
-formatOneline ini_cv plc_len fin_cv =
- printf "%.8f %d %.8f %8.3f" ini_cv plc_len fin_cv
- (if fin_cv == 0 then 1 else (ini_cv / fin_cv))
+options :: [OptType]
+options = [oPrintNodes, oShowVer, oShowHelp]
+
+processResults :: (Monad m) =>
+ RqType -> Cluster.AllocSolution
+ -> m (String, Cluster.AllocSolution)
+processResults _ (_, _, []) = fail "No valid allocation solutions"
+processResults (Evacuate _) as@(fstats, successes, sols) =
+ let best = fst $ head sols
+ tfails = length fstats
+ info = printf "for last allocation, successes %d, failures %d,\
+ \ best score: %.8f" successes tfails best::String
+ in return (info, as)
+
+processResults _ as@(fstats, successes, sols) =
+ case sols of
+ (best, (_, _, w)):[] ->
+ let tfails = length fstats
+ info = printf "successes %d, failures %d,\
+ \ best score: %.8f for node(s) %s"
+ successes tfails
+ best (intercalate "/" . map Node.name $ w)::String
+ in return (info, as)
+ _ -> fail "Internal error: multiple allocation solutions"
+
+-- | Process a request and return new node lists
+processRequest :: Request
+ -> Result Cluster.AllocSolution
+processRequest request =
+ let Request rqtype nl il _ = request
+ in case rqtype of
+ Allocate xi reqn -> Cluster.tryAlloc nl il xi reqn
+ Relocate idx reqn exnodes -> Cluster.tryReloc nl il idx reqn exnodes
+ Evacuate exnodes -> Cluster.tryEvac nl il exnodes