Statistics
| Branch: | Tag: | Revision:

root / hail.hs @ ed41c179

History | View | Annotate | Download (5.7 kB)

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

    
3
-}
4

    
5
module Main (main) where
6

    
7
import Data.List
8
import Data.Function
9
import Data.Maybe (isJust, fromJust, fromMaybe)
10
import Monad
11
import System
12
import System.IO
13
import System.Console.GetOpt
14
import qualified System
15

    
16
import Text.Printf (printf)
17

    
18
import qualified Ganeti.HTools.Container as Container
19
import qualified Ganeti.HTools.Cluster as Cluster
20
import qualified Ganeti.HTools.Node as Node
21
import qualified Ganeti.HTools.Instance as Instance
22
import qualified Ganeti.HTools.CLI as CLI
23
import Ganeti.HTools.IAlloc
24
import Ganeti.HTools.Utils
25
import Ganeti.HTools.Types
26

    
27
-- | Command line options structure.
28
data Options = Options
29
    { optShowNodes :: Bool           -- ^ Whether to show node status
30
    , optShowCmds  :: Maybe FilePath -- ^ Whether to show the command list
31
    , optOneline   :: Bool           -- ^ Switch output to a single line
32
    , optNodef     :: FilePath       -- ^ Path to the nodes file
33
    , optNodeSet   :: Bool           -- ^ The nodes have been set by options
34
    , optInstf     :: FilePath       -- ^ Path to the instances file
35
    , optInstSet   :: Bool           -- ^ The insts have been set by options
36
    , optMaxLength :: Int            -- ^ Stop after this many steps
37
    , optMaster    :: String         -- ^ Collect data from RAPI
38
    , optVerbose   :: Int            -- ^ Verbosity level
39
    , optOffline   :: [String]       -- ^ Names of offline nodes
40
    , optMinScore  :: Cluster.Score  -- ^ The minimum score we aim for
41
    , optShowVer   :: Bool           -- ^ Just show the program version
42
    , optShowHelp  :: Bool           -- ^ Just show the help
43
    } deriving Show
44

    
45
instance CLI.CLIOptions Options where
46
    showVersion = optShowVer
47
    showHelp    = optShowHelp
48

    
49
-- | Default values for the command line options.
50
defaultOptions :: Options
51
defaultOptions  = Options
52
 { optShowNodes = False
53
 , optShowCmds  = Nothing
54
 , optOneline   = False
55
 , optNodef     = "nodes"
56
 , optNodeSet   = False
57
 , optInstf     = "instances"
58
 , optInstSet   = False
59
 , optMaxLength = -1
60
 , optMaster    = ""
61
 , optVerbose   = 1
62
 , optOffline   = []
63
 , optMinScore  = 1e-9
64
 , optShowVer   = False
65
 , optShowHelp  = False
66
 }
67

    
68
-- | Options list and functions
69
options :: [OptDescr (Options -> Options)]
70
options =
71
    [ Option ['p']     ["print-nodes"]
72
      (NoArg (\ opts -> opts { optShowNodes = True }))
73
      "print the final node list"
74
    , Option ['C']     ["print-commands"]
75
      (OptArg ((\ f opts -> opts { optShowCmds = Just f }) . fromMaybe "-")
76
                  "FILE")
77
      "print the ganeti command list for reaching the solution,\
78
      \if an argument is passed then write the commands to a file named\
79
      \ as such"
80
    , Option ['o']     ["oneline"]
81
      (NoArg (\ opts -> opts { optOneline = True }))
82
      "print the ganeti command list for reaching the solution"
83
    , Option ['n']     ["nodes"]
84
      (ReqArg (\ f opts -> opts { optNodef = f, optNodeSet = True }) "FILE")
85
      "the node list FILE"
86
    , Option ['i']     ["instances"]
87
      (ReqArg (\ f opts -> opts { optInstf =  f, optInstSet = True }) "FILE")
88
      "the instance list FILE"
89
    , Option ['m']     ["master"]
90
      (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS")
91
      "collect data via RAPI at the given ADDRESS"
92
    , Option ['l']     ["max-length"]
93
      (ReqArg (\ i opts -> opts { optMaxLength =  (read i)::Int }) "N")
94
      "cap the solution at this many moves (useful for very unbalanced \
95
      \clusters)"
96
    , Option ['v']     ["verbose"]
97
      (NoArg (\ opts -> opts { optVerbose = (optVerbose opts) + 1 }))
98
      "increase the verbosity level"
99
    , Option ['q']     ["quiet"]
100
      (NoArg (\ opts -> opts { optVerbose = (optVerbose opts) - 1 }))
101
      "decrease the verbosity level"
102
    , Option ['O']     ["offline"]
103
      (ReqArg (\ n opts -> opts { optOffline = n:optOffline opts }) "NODE")
104
      " set node as offline"
105
    , Option ['e']     ["min-score"]
106
      (ReqArg (\ e opts -> opts { optMinScore = read e }) "EPSILON")
107
      " mininum score to aim for"
108
    , Option ['V']     ["version"]
109
      (NoArg (\ opts -> opts { optShowVer = True}))
110
      "show the version of the program"
111
    , Option ['h']     ["help"]
112
      (NoArg (\ opts -> opts { optShowHelp = True}))
113
      "show help"
114
    ]
115

    
116
-- | Try to allocate an instance on the cluster
117
tryAlloc :: NodeList
118
         -> InstanceList
119
         -> Instance.Instance
120
         -> Int
121
         -> Result [Node.Node]
122
tryAlloc nl il xi _ = Bad "alloc not implemented"
123

    
124
-- | Try to allocate an instance on the cluster
125
tryReloc :: NodeList
126
         -> InstanceList
127
         -> Int
128
         -> Int
129
         -> [Int]
130
         -> Result [Node.Node]
131
tryReloc nl il xid reqn ex_idx =
132
    let all_nodes = Container.elems nl
133
        valid_nodes = filter (not . flip elem ex_idx . idx) all_nodes
134
    in Ok (take reqn valid_nodes)
135

    
136
-- | Main function.
137
main :: IO ()
138
main = do
139
  cmd_args <- System.getArgs
140
  (opts, args) <- CLI.parseOpts cmd_args "hail" options
141
                  defaultOptions
142

    
143
  when (null args) $ do
144
         hPutStrLn stderr "Error: this program needs an input file."
145
         exitWith $ ExitFailure 1
146

    
147
  let input_file = head args
148
  input_data <- readFile input_file
149

    
150
  request <- case (parseData input_data) of
151
               Bad err -> do
152
                 putStrLn $ "Error: " ++ err
153
                 exitWith $ ExitFailure 1
154
               Ok rq -> return rq
155

    
156
  let Request rqtype nl il csf = request
157
      new_nodes = case rqtype of
158
                    Allocate xi reqn -> tryAlloc nl il xi reqn
159
                    Relocate idx reqn exnodes ->
160
                        tryReloc nl il idx reqn exnodes
161
  let (ok, info, rn) = case new_nodes of
162
               Ok sn -> (True, "Request successfull", map name sn)
163
               Bad s -> (False, "Request failed: " ++ s, [])
164
      resp = formatResponse ok info rn
165
  putStrLn resp