1 {-| Solver for N+1 cluster errors
7 Copyright (C) 2009 Google Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 module Main (main) where
30 import Data.Maybe (isJust, fromJust)
34 import System.Console.GetOpt
35 import qualified System
37 import Text.Printf (printf)
39 import qualified Ganeti.HTools.Container as Container
40 import qualified Ganeti.HTools.Cluster as Cluster
41 import qualified Ganeti.HTools.Node as Node
42 import qualified Ganeti.HTools.Instance as Instance
43 import qualified Ganeti.HTools.CLI as CLI
44 import Ganeti.HTools.IAlloc
45 import Ganeti.HTools.Types
46 import Ganeti.HTools.Loader (RqType(..), Request(..))
47 import Ganeti.HTools.Utils
49 -- | Command line options structure.
50 data Options = Options
51 { optShowVer :: Bool -- ^ Just show the program version
52 , optShowHelp :: Bool -- ^ Just show the help
55 -- | Default values for the command line options.
56 defaultOptions :: Options
57 defaultOptions = Options
62 instance CLI.CLIOptions Options where
63 showVersion = optShowVer
64 showHelp = optShowHelp
66 -- | Options list and functions
67 options :: [OptDescr (Options -> Options)]
69 [ Option ['V'] ["version"]
70 (NoArg (\ opts -> opts { optShowVer = True}))
71 "show the version of the program"
72 , Option ['h'] ["help"]
73 (NoArg (\ opts -> opts { optShowHelp = True}))
78 filterFails :: (Monad m) => [(Maybe Node.List, Instance.Instance, [Node.Node])]
79 -> m [(Node.List, [Node.Node])]
81 if null sols then fail "No nodes onto which to allocate at all"
82 else let sols' = filter (isJust . fst3) sols
84 fail "No valid allocation solutions"
86 return $ map (\(x, _, y) -> (fromJust x, y)) sols'
88 processResults :: (Monad m) => [(Node.List, [Node.Node])]
89 -> m (String, [Node.Node])
91 let sols' = map (\(nl', ns) -> (Cluster.compCV nl', ns)) sols
92 sols'' = sortBy (compare `on` fst) sols'
93 (best, w) = head sols''
94 (worst, l) = last sols''
95 info = (printf "Valid results: %d, best score: %.8f for node(s) %s, \
96 \worst score: %.8f for node(s) %s" (length sols'')
97 best (intercalate "/" . map Node.name $ w)
98 worst (intercalate "/" . map Node.name $ l))::String
101 -- | Process a request and return new node lists
104 -> Result [(Maybe Node.List, Instance.Instance, [Node.Node])]
105 processRequest request =
106 let Request rqtype nl il _ = request
108 Allocate xi reqn -> Cluster.tryAlloc nl il xi reqn
109 Relocate idx reqn exnodes -> Cluster.tryReloc nl il idx reqn exnodes
114 cmd_args <- System.getArgs
115 (_, args) <- CLI.parseOpts cmd_args "hail" options defaultOptions
117 when (null args) $ do
118 hPutStrLn stderr "Error: this program needs an input file."
119 exitWith $ ExitFailure 1
121 let input_file = head args
122 input_data <- readFile input_file
124 request <- case (parseData input_data) of
126 putStrLn $ "Error: " ++ err
127 exitWith $ ExitFailure 1
130 let Request _ _ _ csf = request
131 sols = processRequest request >>= filterFails >>= processResults
132 let (ok, info, rn) = case sols of
133 Ok (info, sn) -> (True, "Request successful: " ++ info,
134 map ((++ csf) . Node.name) sn)
135 Bad s -> (False, "Request failed: " ++ s, [])
136 resp = formatResponse ok info rn