Statistics
| Branch: | Tag: | Revision:

root / hn1.hs @ 75d1edf8

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