Statistics
| Branch: | Tag: | Revision:

root / hn1.hs @ 0a8dd21d

History | View | Annotate | Download (7.6 kB)

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

    
3
-}
4

    
5
{-
6

    
7
Copyright (C) 2009 Google Inc.
8

    
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
13

    
14
This program is distributed in the hope that it will be useful, but
15
WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
General Public License for more details.
18

    
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22
02110-1301, USA.
23

    
24
-}
25

    
26
module Main (main) where
27

    
28
import Data.List
29
import Data.Function
30
import Monad
31
import System
32
import System.IO
33
import System.Console.GetOpt
34
import qualified System
35

    
36
import Text.Printf (printf)
37

    
38
import qualified Ganeti.HTools.Container as Container
39
import qualified Ganeti.HTools.Instance as Instance
40
import qualified Ganeti.HTools.Node as Node
41
import qualified Ganeti.HTools.Cluster as Cluster
42
import qualified Ganeti.HTools.CLI as CLI
43

    
44
-- | Command line options structure.
45
data Options = Options
46
    { optShowNodes   :: Bool
47
    , optShowCmds    :: Bool
48
    , optNodef       :: FilePath
49
    , optNodeSet     :: Bool     -- ^ The nodes have been set by options
50
    , optInstf       :: FilePath -- ^ Path to the instances file
51
    , optInstSet     :: Bool     -- ^ The insts have been set by options
52
    , optMinDepth    :: Int
53
    , optMaxRemovals :: Int
54
    , optMinDelta    :: Int
55
    , optMaxDelta    :: Int
56
    , optMaster      :: String
57
    , optShowVer     :: Bool     -- ^ Just show the program version
58
    , optShowHelp    :: Bool     -- ^ Just show the help
59
    } deriving Show
60

    
61
instance CLI.CLIOptions Options where
62
    showVersion = optShowVer
63
    showHelp    = optShowHelp
64

    
65
instance CLI.EToolOptions Options where
66
    nodeFile   = optNodef
67
    nodeSet    = optNodeSet
68
    instFile   = optInstf
69
    instSet    = optInstSet
70
    masterName = optMaster
71
    silent _   = False
72

    
73
-- | Default values for the command line options.
74
defaultOptions :: Options
75
defaultOptions    = Options
76
 { optShowNodes   = False
77
 , optShowCmds    = False
78
 , optNodef       = "nodes"
79
 , optNodeSet     = False
80
 , optInstf       = "instances"
81
 , optInstSet     = False
82
 , optMinDepth    = 1
83
 , optMaxRemovals = -1
84
 , optMinDelta    = 0
85
 , optMaxDelta    = -1
86
 , optMaster      = ""
87
 , optShowVer     = False
88
 , optShowHelp    = False
89
 }
90

    
91
{- | Start computing the solution at the given depth and recurse until
92
we find a valid solution or we exceed the maximum depth.
93

    
94
-}
95
iterateDepth :: Node.List
96
             -> [Instance.Instance]
97
             -> Int
98
             -> Int
99
             -> Int
100
             -> Int
101
             -> IO (Maybe Cluster.Solution)
102
iterateDepth nl bad_instances depth max_removals min_delta max_delta =
103
    let
104
        max_depth = length bad_instances
105
        sol = Cluster.computeSolution nl bad_instances depth
106
              max_removals min_delta max_delta
107
    in
108
      do
109
        printf "%d " depth
110
        hFlush stdout
111
        case sol `seq` sol of
112
          Nothing ->
113
              if depth > max_depth then
114
                  return Nothing
115
              else
116
                  iterateDepth nl bad_instances (depth + 1)
117
                               max_removals min_delta max_delta
118
          _ -> return sol
119

    
120
-- | Options list and functions
121
options :: [OptDescr (Options -> Options)]
122
options =
123
    [ Option ['p']     ["print-nodes"]
124
      (NoArg (\ opts -> opts { optShowNodes = True }))
125
      "print the final node list"
126
    , Option ['C']     ["print-commands"]
127
      (NoArg (\ opts -> opts { optShowCmds = True }))
128
      "print the ganeti command list for reaching the solution"
129
    , Option ['n']     ["nodes"]
130
      (ReqArg (\ f opts -> opts { optNodef = f, optNodeSet = True }) "FILE")
131
      "the node list FILE"
132
    , Option ['i']     ["instances"]
133
      (ReqArg (\ f opts -> opts { optInstf =  f, optInstSet = True }) "FILE")
134
      "the instance list FILE"
135
    , Option ['d']     ["depth"]
136
      (ReqArg (\ i opts -> opts { optMinDepth =  (read i)::Int }) "D")
137
      "start computing the solution at depth D"
138
    , Option ['r']     ["max-removals"]
139
      (ReqArg (\ i opts -> opts { optMaxRemovals =  (read i)::Int }) "R")
140
      "do not process more than R removal sets (useful for high depths)"
141
    , Option ['L']     ["max-delta"]
142
      (ReqArg (\ i opts -> opts { optMaxDelta =  (read i)::Int }) "L")
143
      "refuse solutions with delta higher than L"
144
    , Option ['l']     ["min-delta"]
145
      (ReqArg (\ i opts -> opts { optMinDelta =  (read i)::Int }) "L")
146
      "return once a solution with delta L or lower has been found"
147
    , Option ['m']     ["master"]
148
      (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS")
149
      "collect data via RAPI at the given ADDRESS"
150
    , Option ['V']     ["version"]
151
      (NoArg (\ opts -> opts { optShowVer = True}))
152
      "show the version of the program"
153
    , Option ['h']     ["help"]
154
      (NoArg (\ opts -> opts { optShowHelp = True}))
155
      "show help"
156
    ]
157

    
158
-- | Main function.
159
main :: IO ()
160
main = do
161
  cmd_args <- System.getArgs
162
  (opts, args) <- CLI.parseOpts cmd_args "hn1" options
163
                  defaultOptions
164

    
165
  unless (null args) $ do
166
         hPutStrLn stderr "Error: this program doesn't take any arguments."
167
         exitWith $ ExitFailure 1
168

    
169
  (nl, il, csf) <- CLI.loadExternalData opts
170

    
171
  printf "Loaded %d nodes, %d instances\n"
172
             (Container.size nl)
173
             (Container.size il)
174

    
175
  when (length csf > 0) $ do
176
         printf "Note: Stripping common suffix of '%s' from names\n" csf
177

    
178
  let (bad_nodes, bad_instances) = Cluster.computeBadItems nl il
179
      min_depth = optMinDepth opts
180

    
181
  printf "Initial check done: %d bad nodes, %d bad instances.\n"
182
             (length bad_nodes) (length bad_instances)
183

    
184
  when (null bad_instances) $ do
185
         putStrLn "Happy time! Cluster is fine, no need to burn CPU."
186
         exitWith ExitSuccess
187

    
188
  when (length bad_instances < min_depth) $ do
189
         printf "Error: depth %d is higher than the number of bad instances.\n"
190
                min_depth
191
         exitWith $ ExitFailure 2
192

    
193
  let ini_cv = Cluster.compCV nl
194
  printf "Initial coefficients: overall %.8f, %s\n"
195
         ini_cv (Cluster.printStats nl)
196

    
197
  putStr "Computing solution: depth "
198
  hFlush stdout
199

    
200
  result <- iterateDepth nl bad_instances min_depth (optMaxRemovals opts)
201
            (optMinDelta opts) (optMaxDelta opts)
202
  let (min_d, solution) =
203
          case result of
204
            Just (Cluster.Solution a b) -> (a, reverse b)
205
            Nothing -> (-1, [])
206
  when (min_d == -1) $ do
207
         putStrLn "failed. Try to run with higher depth."
208
         exitWith $ ExitFailure 1
209

    
210
  printf "found.\n"
211

    
212
  let
213
      ns = Cluster.applySolution nl il solution
214
      fin_cv = Cluster.compCV ns
215

    
216
  printf "Final coefficients:   overall %.8f, %s\n"
217
         fin_cv
218
         (Cluster.printStats ns)
219

    
220
  printf "Solution (delta=%d):\n" $! min_d
221
  let (sol_strs, cmd_strs) = Cluster.printSolution ns il solution
222
  putStr $ unlines $ sol_strs
223
  when (optShowCmds opts) $
224
       do
225
         putStrLn ""
226
         putStrLn "Commands to run to reach the above solution:"
227
         putStr . Cluster.formatCmds . reverse $ cmd_strs
228

    
229
  when (optShowNodes opts) $
230
       do
231
         let (orig_mem, orig_disk) = Cluster.totalResources nl
232
             (final_mem, final_disk) = Cluster.totalResources ns
233
         putStrLn ""
234
         putStrLn "Final cluster status:"
235
         putStrLn $ Cluster.printNodes ns
236
         printf "Original: mem=%d disk=%d\n" orig_mem orig_disk
237
         printf "Final:    mem=%d disk=%d\n" final_mem final_disk