Revision 914c6df4

b/src/Ganeti/HTools/CLI.hs
232 232
  let sp = sepSplit ',' inp
233 233
      err = Bad ("Invalid " ++ descr ++ " specification: '" ++ inp ++
234 234
                 "', expected disk,ram,cpu")
235
  when (length sp /= 3) err
235
  when (length sp < 3 || length sp > 4) err
236 236
  prs <- mapM (\(fn, val) -> fn val) $
237 237
         zip [ annotateResult (descr ++ " specs disk") . parseUnit
238 238
             , annotateResult (descr ++ " specs memory") . parseUnit
239 239
             , tryRead (descr ++ " specs cpus")
240
             , tryRead (descr ++ " specs spindles")
240 241
             ] sp
241 242
  case prs of
242
    [dsk, ram, cpu] -> return $ RSpec cpu ram dsk
243
    {- Spindles are optional, so that they are not needed when exclusive storage
244
       is disabled. When exclusive storage is disabled, spindles are ignored,
245
       so the actual value doesn't matter. We use 1 as a default so that in
246
       case someone forgets and exclusive storage is enabled, we don't run into
247
       weird situations. -}
248
    [dsk, ram, cpu] -> return $ RSpec cpu ram dsk 1
249
    [dsk, ram, cpu, spn] -> return $ RSpec cpu ram dsk spn
243 250
    _ -> err
244 251

  
245 252
-- | Disk template choices.
b/src/Ganeti/HTools/Instance.hs
274 274

  
275 275
-- | Return the spec of an instance.
276 276
specOf :: Instance -> T.RSpec
277
specOf Instance { mem = m, dsk = d, vcpus = c } =
278
  T.RSpec { T.rspecCpu = c, T.rspecMem = m, T.rspecDsk = d }
277
specOf Instance { mem = m, dsk = d, vcpus = c, disks = dl } =
278
  let sp = case dl of
279
             [Disk _ (Just sp')] -> sp'
280
             _ -> 0
281
  in T.RSpec { T.rspecCpu = c, T.rspecMem = m,
282
               T.rspecDsk = d, T.rspecSpn = sp }
279 283

  
280 284
-- | Checks if an instance is smaller/bigger than a given spec. Returns
281 285
-- OpGood for a correct spec, otherwise Bad one of the possible
b/src/Ganeti/HTools/Program/Hspace.hs
396 396
instFromSpec :: RSpec -> DiskTemplate -> Int -> Instance.Instance
397 397
instFromSpec spx dt su =
398 398
  Instance.create "new" (rspecMem spx) (rspecDsk spx)
399
    [Instance.Disk (rspecDsk spx) (Just su)]
399
    [Instance.Disk (rspecDsk spx) (Just $ rspecSpn spx)]
400 400
    (rspecCpu spx) Running [] True (-1) (-1) dt su []
401 401

  
402 402
combineTiered :: Maybe Int -> Cluster.AllocNodes -> Cluster.AllocResult ->
b/src/Ganeti/HTools/Types.hs
142 142
  { rspecCpu  :: Int  -- ^ Requested VCPUs
143 143
  , rspecMem  :: Int  -- ^ Requested memory
144 144
  , rspecDsk  :: Int  -- ^ Requested disk
145
  , rspecSpn  :: Int  -- ^ Requested spindles
145 146
  } deriving (Show, Eq)
146 147

  
147 148
-- | Allocation stats type. This is used instead of 'RSpec' (which was
......
232 233
rspecFromISpec ispec = RSpec { rspecCpu = iSpecCpuCount ispec
233 234
                             , rspecMem = iSpecMemorySize ispec
234 235
                             , rspecDsk = iSpecDiskSize ispec
236
                             , rspecSpn = iSpecSpindleUse ispec
235 237
                             }
236 238

  
237 239
-- | The default instance policy.
b/test/hs/Test/Ganeti/HTools/CLI.hs
47 47
{-# ANN module "HLint: ignore Use camelCase" #-}
48 48

  
49 49
-- | Test correct parsing.
50
prop_parseISpec :: String -> Int -> Int -> Int -> Property
51
prop_parseISpec descr dsk mem cpu =
52
  let str = printf "%d,%d,%d" dsk mem cpu::String
53
  in parseISpecString descr str ==? Ok (Types.RSpec cpu mem dsk)
50
prop_parseISpec :: String -> Int -> Int -> Int -> Maybe Int -> Property
51
prop_parseISpec descr dsk mem cpu spn =
52
  let (str, spn') = case spn of
53
                      Nothing -> (printf "%d,%d,%d" dsk mem cpu::String, 1)
54
                      Just spn'' ->
55
                        (printf "%d,%d,%d,%d" dsk mem cpu spn''::String, spn'')
56
  in parseISpecString descr str ==? Ok (Types.RSpec cpu mem dsk spn')
54 57

  
55 58
-- | Test parsing failure due to wrong section count.
56 59
prop_parseISpecFail :: String -> Property
57 60
prop_parseISpecFail descr =
58
  forAll (choose (0,100) `suchThat` (/= 3)) $ \nelems ->
61
  forAll (choose (0,100) `suchThat` (not . flip elem [3, 4])) $ \nelems ->
59 62
  forAll (replicateM nelems arbitrary) $ \values ->
60 63
  let str = intercalate "," $ map show (values::[Int])
61 64
  in case parseISpecString descr str of

Also available in: Unified diff