Statistics
| Branch: | Tag: | Revision:

root / hn1.hs @ 669d7e3d

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