Revision b2278348

b/Ganeti/HTools/CLI.hs
43 43
    , oOutputDir
44 44
    , oNodeFile
45 45
    , oInstFile
46
    , oNodeSim
46 47
    , oRapiMaster
47 48
    , oLuxiSocket
48 49
    , oMaxSolLength
......
74 75
import qualified Ganeti.HTools.Version as Version(version)
75 76
import qualified Ganeti.HTools.Luxi as Luxi
76 77
import qualified Ganeti.HTools.Rapi as Rapi
78
import qualified Ganeti.HTools.Simu as Simu
77 79
import qualified Ganeti.HTools.Text as Text
78 80
import qualified Ganeti.HTools.Loader as Loader
79 81
import qualified Ganeti.HTools.Instance as Instance
......
97 99
    , optNodeSet   :: Bool           -- ^ The nodes have been set by options
98 100
    , optInstFile  :: FilePath       -- ^ Path to the instances file
99 101
    , optInstSet   :: Bool           -- ^ The insts have been set by options
102
    , optNodeSim   :: Maybe String   -- ^ Cluster simulation mode
100 103
    , optMaxLength :: Int            -- ^ Stop after this many steps
101 104
    , optMaster    :: String         -- ^ Collect data from RAPI
102 105
    , optLuxi      :: Maybe FilePath -- ^ Collect data from Luxi
......
125 128
 , optNodeSet   = False
126 129
 , optInstFile  = "instances"
127 130
 , optInstSet   = False
131
 , optNodeSim   = Nothing
128 132
 , optMaxLength = -1
129 133
 , optMaster    = ""
130 134
 , optLuxi      = Nothing
......
183 187
            (ReqArg (\ f o -> o { optInstFile = f, optInstSet = True }) "FILE")
184 188
            "the instance list FILE"
185 189

  
190
oNodeSim :: OptType
191
oNodeSim = Option "" ["simulate"]
192
            (ReqArg (\ f o -> o { optNodeSim = Just f }) "SPEC")
193
            "simulate an empty cluster, given as 'num_nodes,disk,memory,cpus'"
194

  
186 195
oRapiMaster :: OptType
187 196
oRapiMaster = Option "m" ["master"]
188 197
              (ReqArg (\ m opts -> opts { optMaster = m }) "ADDRESS")
......
330 339
              else env_inst
331 340
      mhost = optMaster opts
332 341
      lsock = optLuxi opts
342
      simdata = optNodeSim opts
333 343
      setRapi = mhost /= ""
334 344
      setLuxi = isJust lsock
345
      setSim = isJust simdata
335 346
      setFiles = optNodeSet opts || optInstSet opts
336 347
      allSet = filter id [setRapi, setLuxi, setFiles]
337 348
  when (length allSet > 1) $
......
344 355
      case () of
345 356
        _ | setRapi -> wrapIO $ Rapi.loadData mhost
346 357
          | setLuxi -> wrapIO $ Luxi.loadData $ fromJust lsock
358
          | setSim -> Simu.loadData $ fromJust simdata
347 359
          | otherwise -> wrapIO $ Text.loadData nodef instf
348 360

  
349 361
  let ldresult = input_data >>= Loader.mergeData
b/Ganeti/HTools/Simu.hs
1
{-| Parsing data from a simulated description of the cluster
2

  
3
This module holds the code for parsing a cluster description.
4

  
5
-}
6

  
7
{-
8

  
9
Copyright (C) 2009 Google Inc.
10

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

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

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

  
26
-}
27

  
28
module Ganeti.HTools.Simu
29
    (
30
      loadData
31
    ) where
32

  
33
import Control.Monad
34
import Text.Printf (printf)
35

  
36
import Ganeti.HTools.Utils
37
import Ganeti.HTools.Types
38
import qualified Ganeti.HTools.Node as Node
39
import qualified Ganeti.HTools.Instance as Instance
40

  
41
-- | Parse results from readsPrec
42
parseChoices :: (Monad m, Read a) => String -> String -> [(a, String)] -> m a
43
parseChoices _ _ ((v, ""):[]) = return v
44
parseChoices name s ((_, e):[]) =
45
    fail $ name ++ ": leftover characters when parsing '"
46
           ++ s ++ "': '" ++ e ++ "'"
47
parseChoices name s _ = fail $ name ++ ": cannot parse string '" ++ s ++ "'"
48

  
49
-- | Safe 'read' function returning data encapsulated in a Result.
50
tryRead :: (Monad m, Read a) => String -> String -> m a
51
tryRead name s = parseChoices name s $ reads s
52

  
53
-- | Parse the string description into nodes
54
parseDesc :: String -> Result (Int, Int, Int, Int)
55
parseDesc desc =
56
    case sepSplit ',' desc of
57
      n:d:m:c:[] -> do
58
        ncount <- tryRead "node count" n
59
        disk <- tryRead "disk size" d
60
        mem <- tryRead "memory size" m
61
        cpu <- tryRead "cpu count" c
62
        return (ncount, disk, mem, cpu)
63
      _ -> fail "Invalid cluster specification"
64

  
65
-- | Builds the cluster data from node\/instance files.
66
loadData :: String -- ^ Cluster description in text format
67
         -> IO (Result (Node.AssocList, Instance.AssocList))
68
loadData ndata = -- IO monad, just for consistency with the other loaders
69
  return $ do
70
    (cnt, disk, mem, cpu) <- parseDesc ndata
71
    let nodes = map (\idx ->
72
                         let n = Node.create (printf "node%03d" idx)
73
                                 (fromIntegral mem) 0 mem
74
                                 (fromIntegral disk) disk
75
                                 (fromIntegral cpu) False
76
                         in (idx, Node.setIdx n idx)
77
                    ) [1..cnt]
78
    return (nodes, [])
b/Ganeti/HTools/Text.hs
27 27
-}
28 28

  
29 29
module Ganeti.HTools.Text
30
    where
30
    (
31
      loadData
32
    ) where
31 33

  
32 34
import Control.Monad
33 35

  
b/hspace.1
300 300
used by ganeti when installed with "--localstatedir=/var" is used.
301 301

  
302 302
.TP
303
.BI "--simulate " description
304
Instead of using actual data, build an empty cluster given a node
305
description. The \fIdescription\fR parameter must be a comma-separate
306
list of four elements, describing in order:
307

  
308
.RS
309

  
310
.RS
311
.TP
312
the number of nodes in the cluster
313

  
314
.TP
315
the disk size of the nodes, in mebibytes
316

  
317
.TP
318
the memory size of the nodes, in mebibytes
319

  
320
.TP
321
the cpu core count for the nodes
322

  
323
.RE
324

  
325
An example description would be \fB20,102400,16384,4\fR describing a
326
20-node cluster where each node has 100GiB of disk space, 16GiB of
327
memory and 4 CPU cores. Note that all nodes must have the same specs
328
currently.
329

  
330
.RE
331

  
332
.TP
303 333
.B -v, --verbose
304 334
Increase the output verbosity. Each usage of this option will increase
305 335
the verbosity (currently more than 2 doesn't make sense) from the
b/hspace.hs
50 50
    [ oPrintNodes
51 51
    , oNodeFile
52 52
    , oInstFile
53
    , oNodeSim
53 54
    , oRapiMaster
54 55
    , oLuxiSocket
55 56
    , oVerbose

Also available in: Unified diff