Statistics
| Branch: | Tag: | Revision:

root / hail.hs @ dbba5246

History | View | Annotate | Download (3.5 kB)

1
{-| Solver for N+1 cluster errors
2

    
3
-}
4

    
5
module Main (main) where
6

    
7
import Data.List
8
import Data.Function
9
import Data.Maybe (isJust, fromJust)
10
import Monad
11
import System
12
import System.IO
13
import System.Console.GetOpt
14
import qualified System
15

    
16
import Text.Printf (printf)
17

    
18
import qualified Ganeti.HTools.Container as Container
19
import qualified Ganeti.HTools.Cluster as Cluster
20
import qualified Ganeti.HTools.Node as Node
21
import qualified Ganeti.HTools.Instance as Instance
22
import qualified Ganeti.HTools.CLI as CLI
23
import Ganeti.HTools.IAlloc
24
import Ganeti.HTools.Types
25
import Ganeti.HTools.Loader (RqType(..), Request(..))
26

    
27
-- | Command line options structure.
28
data Options = Options
29
    { optShowVer   :: Bool           -- ^ Just show the program version
30
    , optShowHelp  :: Bool           -- ^ Just show the help
31
    } deriving Show
32

    
33
-- | Default values for the command line options.
34
defaultOptions :: Options
35
defaultOptions  = Options
36
 { optShowVer   = False
37
 , optShowHelp  = False
38
 }
39

    
40
instance CLI.CLIOptions Options where
41
    showVersion = optShowVer
42
    showHelp    = optShowHelp
43

    
44
-- | Options list and functions
45
options :: [OptDescr (Options -> Options)]
46
options =
47
    [ Option ['V']     ["version"]
48
      (NoArg (\ opts -> opts { optShowVer = True}))
49
      "show the version of the program"
50
    , Option ['h']     ["help"]
51
      (NoArg (\ opts -> opts { optShowHelp = True}))
52
      "show help"
53
    ]
54

    
55

    
56
filterFails :: (Monad m) => [(Maybe Node.List, [Node.Node])]
57
            -> m [(Node.List, [Node.Node])]
58
filterFails sols =
59
    if null sols then fail "No nodes onto which to allocate at all"
60
    else let sols' = filter (isJust . fst) sols
61
         in if null sols' then
62
                fail "No valid allocation solutions"
63
            else
64
                return $ map (\(x, y) -> (fromJust x, y)) sols'
65

    
66
processResults :: (Monad m) => [(Node.List, [Node.Node])]
67
               -> m (String, [Node.Node])
68
processResults sols =
69
    let sols' = map (\(nl', ns) -> (Cluster.compCV  nl', ns)) sols
70
        sols'' = sortBy (compare `on` fst) sols'
71
        (best, w) = head sols''
72
        (worst, l) = last sols''
73
        info = printf "Valid results: %d, best score: %.8f for node(s) %s, \
74
                      \worst score: %.8f for node(s) %s" (length sols'')
75
                      best (intercalate "/" . map Node.name $ w)
76
                      worst (intercalate "/" . map Node.name $ l)
77
    in return (info, w)
78

    
79
-- | Main function.
80
main :: IO ()
81
main = do
82
  cmd_args <- System.getArgs
83
  (_, args) <- CLI.parseOpts cmd_args "hail" options defaultOptions
84

    
85
  when (null args) $ do
86
         hPutStrLn stderr "Error: this program needs an input file."
87
         exitWith $ ExitFailure 1
88

    
89
  let input_file = head args
90
  input_data <- readFile input_file
91

    
92
  request <- case (parseData input_data) of
93
               Bad err -> do
94
                 putStrLn $ "Error: " ++ err
95
                 exitWith $ ExitFailure 1
96
               Ok rq -> return rq
97

    
98
  let Request rqtype nl il csf = request
99
      new_nodes = case rqtype of
100
                    Allocate xi reqn -> Cluster.tryAlloc nl il xi reqn
101
                    Relocate idx reqn exnodes ->
102
                        Cluster.tryReloc nl il idx reqn exnodes
103
  let sols = new_nodes >>= filterFails >>= processResults
104
  let (ok, info, rn) = case sols of
105
               Ok (info, sn) -> (True, "Request successful: " ++ info,
106
                                     map ((++ csf) . Node.name) sn)
107
               Bad s -> (False, "Request failed: " ++ s, [])
108
      resp = formatResponse ok info rn
109
  putStrLn resp