Statistics
| Branch: | Tag: | Revision:

root / src / hn1.hs @ 0c1df6fd

History | View | Annotate | Download (6.3 kB)

1 e4f08c46 Iustin Pop
{-| Solver for N+1 cluster errors
2 e4f08c46 Iustin Pop
3 e4f08c46 Iustin Pop
-}
4 e4f08c46 Iustin Pop
5 e4f08c46 Iustin Pop
module Main (main) where
6 e4f08c46 Iustin Pop
7 e4f08c46 Iustin Pop
import Data.List
8 e4f08c46 Iustin Pop
import Data.Function
9 e4f08c46 Iustin Pop
import Monad
10 e4f08c46 Iustin Pop
import System
11 e4f08c46 Iustin Pop
import System.IO
12 e4f08c46 Iustin Pop
import System.Console.GetOpt
13 e4f08c46 Iustin Pop
import qualified System
14 e4f08c46 Iustin Pop
15 e4f08c46 Iustin Pop
import Text.Printf (printf)
16 e4f08c46 Iustin Pop
17 e4f08c46 Iustin Pop
import qualified Container
18 e4f08c46 Iustin Pop
import qualified Instance
19 e4f08c46 Iustin Pop
import qualified Cluster
20 dd4c56ed Iustin Pop
import Utils
21 dd4c56ed Iustin Pop
import Rapi
22 e4f08c46 Iustin Pop
23 e4f08c46 Iustin Pop
-- | Command line options structure.
24 e4f08c46 Iustin Pop
data Options = Options
25 e4f08c46 Iustin Pop
    { optShowNodes   :: Bool
26 e4f08c46 Iustin Pop
    , optShowCmds    :: Bool
27 e4f08c46 Iustin Pop
    , optNodef       :: FilePath
28 e4f08c46 Iustin Pop
    , optInstf       :: FilePath
29 e4f08c46 Iustin Pop
    , optMinDepth    :: Int
30 e4f08c46 Iustin Pop
    , optMaxRemovals :: Int
31 e4f08c46 Iustin Pop
    , optMinDelta    :: Int
32 e4f08c46 Iustin Pop
    , optMaxDelta    :: Int
33 dd4c56ed Iustin Pop
    , optMaster    :: String
34 e4f08c46 Iustin Pop
    } deriving Show
35 e4f08c46 Iustin Pop
36 e4f08c46 Iustin Pop
-- | Default values for the command line options.
37 e4f08c46 Iustin Pop
defaultOptions :: Options
38 e4f08c46 Iustin Pop
defaultOptions    = Options
39 e4f08c46 Iustin Pop
 { optShowNodes   = False
40 e4f08c46 Iustin Pop
 , optShowCmds    = False
41 e4f08c46 Iustin Pop
 , optNodef       = "nodes"
42 e4f08c46 Iustin Pop
 , optInstf       = "instances"
43 e4f08c46 Iustin Pop
 , optMinDepth    = 1
44 e4f08c46 Iustin Pop
 , optMaxRemovals = -1
45 e4f08c46 Iustin Pop
 , optMinDelta    = 0
46 e4f08c46 Iustin Pop
 , optMaxDelta    = -1
47 dd4c56ed Iustin Pop
 , optMaster    = ""
48 e4f08c46 Iustin Pop
 }
49 e4f08c46 Iustin Pop
50 e4f08c46 Iustin Pop
{- | Start computing the solution at the given depth and recurse until
51 e4f08c46 Iustin Pop
we find a valid solution or we exceed the maximum depth.
52 e4f08c46 Iustin Pop
53 e4f08c46 Iustin Pop
-}
54 e4f08c46 Iustin Pop
iterateDepth :: Cluster.NodeList
55 e4f08c46 Iustin Pop
             -> [Instance.Instance]
56 e4f08c46 Iustin Pop
             -> Int
57 e4f08c46 Iustin Pop
             -> Int
58 e4f08c46 Iustin Pop
             -> Int
59 e4f08c46 Iustin Pop
             -> Int
60 e4f08c46 Iustin Pop
             -> IO (Maybe Cluster.Solution)
61 e4f08c46 Iustin Pop
iterateDepth nl bad_instances depth max_removals min_delta max_delta =
62 e4f08c46 Iustin Pop
    let
63 e4f08c46 Iustin Pop
        max_depth = length bad_instances
64 e4f08c46 Iustin Pop
        sol = Cluster.computeSolution nl bad_instances depth
65 e4f08c46 Iustin Pop
              max_removals min_delta max_delta
66 e4f08c46 Iustin Pop
    in
67 e4f08c46 Iustin Pop
      do
68 e4f08c46 Iustin Pop
        printf "%d " depth
69 e4f08c46 Iustin Pop
        hFlush stdout
70 e4f08c46 Iustin Pop
        case sol `seq` sol of
71 e4f08c46 Iustin Pop
          Nothing ->
72 e4f08c46 Iustin Pop
              if depth > max_depth then
73 e4f08c46 Iustin Pop
                  return Nothing
74 e4f08c46 Iustin Pop
              else
75 e4f08c46 Iustin Pop
                  iterateDepth nl bad_instances (depth + 1)
76 e4f08c46 Iustin Pop
                               max_removals min_delta max_delta
77 e4f08c46 Iustin Pop
          _ -> return sol
78 e4f08c46 Iustin Pop
79 e4f08c46 Iustin Pop
-- | Options list and functions
80 e4f08c46 Iustin Pop
options :: [OptDescr (Options -> Options)]
81 e4f08c46 Iustin Pop
options =
82 e4f08c46 Iustin Pop
    [ Option ['p']     ["print-nodes"]
83 e4f08c46 Iustin Pop
      (NoArg (\ opts -> opts { optShowNodes = True }))
84 e4f08c46 Iustin Pop
      "print the final node list"
85 e4f08c46 Iustin Pop
    , Option ['C']     ["print-commands"]
86 e4f08c46 Iustin Pop
      (NoArg (\ opts -> opts { optShowCmds = True }))
87 e4f08c46 Iustin Pop
      "print the ganeti command list for reaching the solution"
88 e4f08c46 Iustin Pop
     , Option ['n']     ["nodes"]
89 e4f08c46 Iustin Pop
      (ReqArg (\ f opts -> opts { optNodef = f }) "FILE")
90 e4f08c46 Iustin Pop
      "the node list FILE"
91 e4f08c46 Iustin Pop
     , Option ['i']     ["instances"]
92 e4f08c46 Iustin Pop
      (ReqArg (\ f opts -> opts { optInstf =  f }) "FILE")
93 e4f08c46 Iustin Pop
      "the instance list FILE"
94 e4f08c46 Iustin Pop
     , Option ['d']     ["depth"]
95 e4f08c46 Iustin Pop
      (ReqArg (\ i opts -> opts { optMinDepth =  (read i)::Int }) "D")
96 e4f08c46 Iustin Pop
      "start computing the solution at depth D"
97 e4f08c46 Iustin Pop
     , Option ['r']     ["max-removals"]
98 e4f08c46 Iustin Pop
      (ReqArg (\ i opts -> opts { optMaxRemovals =  (read i)::Int }) "R")
99 e4f08c46 Iustin Pop
      "do not process more than R removal sets (useful for high depths)"
100 e4f08c46 Iustin Pop
     , Option ['L']     ["max-delta"]
101 e4f08c46 Iustin Pop
      (ReqArg (\ i opts -> opts { optMaxDelta =  (read i)::Int }) "L")
102 e4f08c46 Iustin Pop
      "refuse solutions with delta higher than L"
103 e4f08c46 Iustin Pop
     , Option ['l']     ["min-delta"]
104 e4f08c46 Iustin Pop
      (ReqArg (\ i opts -> opts { optMinDelta =  (read i)::Int }) "L")
105 e4f08c46 Iustin Pop
      "return once a solution with delta L or lower has been found"
106 dd4c56ed Iustin Pop
     , Option ['m']     ["master"]
107 dd4c56ed Iustin Pop
      (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS")
108 dd4c56ed Iustin Pop
      "collect data via RAPI at the given ADDRESS"
109 e4f08c46 Iustin Pop
     ]
110 e4f08c46 Iustin Pop
111 e4f08c46 Iustin Pop
-- | Command line parser, using the 'options' structure.
112 e4f08c46 Iustin Pop
parseOpts :: [String] -> IO (Options, [String])
113 e4f08c46 Iustin Pop
parseOpts argv =
114 e4f08c46 Iustin Pop
    case getOpt Permute options argv of
115 e4f08c46 Iustin Pop
      (o,n,[]  ) ->
116 e4f08c46 Iustin Pop
          return (foldl (flip id) defaultOptions o, n)
117 e4f08c46 Iustin Pop
      (_,_,errs) ->
118 e4f08c46 Iustin Pop
          ioError (userError (concat errs ++ usageInfo header options))
119 e4f08c46 Iustin Pop
      where header = "Usage: hn1 [OPTION...]"
120 e4f08c46 Iustin Pop
121 e4f08c46 Iustin Pop
-- | Main function.
122 e4f08c46 Iustin Pop
main :: IO ()
123 e4f08c46 Iustin Pop
main = do
124 e4f08c46 Iustin Pop
  cmd_args <- System.getArgs
125 e4f08c46 Iustin Pop
  (opts, _) <- parseOpts cmd_args
126 e4f08c46 Iustin Pop
  let min_depth = optMinDepth opts
127 dd4c56ed Iustin Pop
  let (node_data, inst_data) =
128 dd4c56ed Iustin Pop
          case optMaster opts of
129 dd4c56ed Iustin Pop
            "" -> (readFile $ optNodef opts,
130 dd4c56ed Iustin Pop
                   readFile $ optInstf opts)
131 dd4c56ed Iustin Pop
            host -> (readData getNodes host,
132 dd4c56ed Iustin Pop
                     readData getInstances host)
133 dd4c56ed Iustin Pop
134 a0529a64 Iustin Pop
  (nl, il, csf, ktn, kti) <- liftM2 Cluster.loadData node_data inst_data
135 dd4c56ed Iustin Pop
136 e4f08c46 Iustin Pop
  printf "Loaded %d nodes, %d instances\n"
137 e4f08c46 Iustin Pop
             (Container.size nl)
138 e4f08c46 Iustin Pop
             (Container.size il)
139 a0529a64 Iustin Pop
140 a0529a64 Iustin Pop
  when (length csf > 0) $ do
141 a0529a64 Iustin Pop
         printf "Note: Stripping common suffix of '%s' from names\n" csf
142 a0529a64 Iustin Pop
143 e4f08c46 Iustin Pop
  let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
144 e4f08c46 Iustin Pop
  printf "Initial check done: %d bad nodes, %d bad instances.\n"
145 e4f08c46 Iustin Pop
             (length bad_nodes) (length bad_instances)
146 e4f08c46 Iustin Pop
147 e4f08c46 Iustin Pop
  when (null bad_instances) $ do
148 e4f08c46 Iustin Pop
         putStrLn "Happy time! Cluster is fine, no need to burn CPU."
149 e4f08c46 Iustin Pop
         exitWith ExitSuccess
150 e4f08c46 Iustin Pop
151 e4f08c46 Iustin Pop
  when (length bad_instances < min_depth) $ do
152 e4f08c46 Iustin Pop
         printf "Error: depth %d is higher than the number of bad instances.\n"
153 e4f08c46 Iustin Pop
                min_depth
154 e4f08c46 Iustin Pop
         exitWith $ ExitFailure 2
155 e4f08c46 Iustin Pop
156 0c1df6fd Iustin Pop
  let ini_cv = Cluster.compCV nl
157 0c1df6fd Iustin Pop
  printf "Initial coefficients: overall %.8f, %s\n"
158 0c1df6fd Iustin Pop
         ini_cv (Cluster.printStats nl)
159 0c1df6fd Iustin Pop
160 e4f08c46 Iustin Pop
  putStr "Computing solution: depth "
161 e4f08c46 Iustin Pop
  hFlush stdout
162 e4f08c46 Iustin Pop
163 e4f08c46 Iustin Pop
  result <- iterateDepth nl bad_instances min_depth (optMaxRemovals opts)
164 e4f08c46 Iustin Pop
            (optMinDelta opts) (optMaxDelta opts)
165 e4f08c46 Iustin Pop
  let (min_d, solution) =
166 e4f08c46 Iustin Pop
          case result of
167 0c1df6fd Iustin Pop
            Just (Cluster.Solution a b) -> (a, reverse b)
168 e4f08c46 Iustin Pop
            Nothing -> (-1, [])
169 e4f08c46 Iustin Pop
  when (min_d == -1) $ do
170 e4f08c46 Iustin Pop
         putStrLn "failed. Try to run with higher depth."
171 e4f08c46 Iustin Pop
         exitWith $ ExitFailure 1
172 e4f08c46 Iustin Pop
173 0c1df6fd Iustin Pop
  printf "found.\n"
174 0c1df6fd Iustin Pop
175 0c1df6fd Iustin Pop
  let
176 0c1df6fd Iustin Pop
      ns = Cluster.applySolution nl il solution
177 0c1df6fd Iustin Pop
      fin_cv = Cluster.compCV ns
178 0c1df6fd Iustin Pop
179 0c1df6fd Iustin Pop
  printf "Final coefficients:   overall %.8f, %s\n"
180 0c1df6fd Iustin Pop
         fin_cv
181 0c1df6fd Iustin Pop
         (Cluster.printStats ns)
182 0c1df6fd Iustin Pop
183 0c1df6fd Iustin Pop
  printf "Solution (delta=%d):\n" $! min_d
184 e4f08c46 Iustin Pop
  let (sol_strs, cmd_strs) = Cluster.printSolution il ktn kti solution
185 e4f08c46 Iustin Pop
  putStr $ unlines $ sol_strs
186 e4f08c46 Iustin Pop
  when (optShowCmds opts) $
187 e4f08c46 Iustin Pop
       do
188 e4f08c46 Iustin Pop
         putStrLn ""
189 e4f08c46 Iustin Pop
         putStrLn "Commands to run to reach the above solution:"
190 e4f08c46 Iustin Pop
         putStr $ unlines $ map ("  echo gnt-instance " ++) $ concat cmd_strs
191 e4f08c46 Iustin Pop
  when (optShowNodes opts) $
192 e4f08c46 Iustin Pop
       do
193 e4f08c46 Iustin Pop
         let (orig_mem, orig_disk) = Cluster.totalResources nl
194 e4f08c46 Iustin Pop
             (final_mem, final_disk) = Cluster.totalResources ns
195 e4f08c46 Iustin Pop
         putStrLn ""
196 e4f08c46 Iustin Pop
         putStrLn "Final cluster status:"
197 e4f08c46 Iustin Pop
         putStrLn $ Cluster.printNodes ktn ns
198 e4f08c46 Iustin Pop
         printf "Original: mem=%d disk=%d\n" orig_mem orig_disk
199 e4f08c46 Iustin Pop
         printf "Final:    mem=%d disk=%d\n" final_mem final_disk