Statistics
| Branch: | Tag: | Revision:

root / hn1.hs @ 8472a321

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