Revision 5a13489b

b/lib/cmdlib/common.py
544 544
  @see: L{ComputeIPolicySpecViolation}
545 545

  
546 546
  """
547
  ret = []
547 548
  be_full = cfg.GetClusterInfo().FillBE(instance)
548 549
  mem_size = be_full[constants.BE_MAXMEM]
549 550
  cpu_count = be_full[constants.BE_VCPUS]
550
  spindle_use = be_full[constants.BE_SPINDLE_USE]
551
  es_flags = rpc.GetExclusiveStorageForNodeNames(cfg, instance.all_nodes)
552
  if any(es_flags.values()):
553
    # With exclusive storage use the actual spindles
554
    try:
555
      spindle_use = sum([disk.spindles for disk in instance.disks])
556
    except TypeError:
557
      ret.append("Number of spindles not configured for disks of instance %s"
558
                 " while exclusive storage is enabled, try running gnt-cluster"
559
                 " repair-disk-sizes" % instance.name)
560
      # _ComputeMinMaxSpec ignores 'None's
561
      spindle_use = None
562
  else:
563
    spindle_use = be_full[constants.BE_SPINDLE_USE]
551 564
  disk_count = len(instance.disks)
552 565
  disk_sizes = [disk.size for disk in instance.disks]
553 566
  nic_count = len(instance.nics)
554 567
  disk_template = instance.disk_template
555 568

  
556
  return _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
557
                     disk_sizes, spindle_use, disk_template)
569
  return ret + _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
570
                           disk_sizes, spindle_use, disk_template)
558 571

  
559 572

  
560 573
def _ComputeViolatingInstances(ipolicy, instances, cfg):
b/src/Ganeti/HTools/Cluster.hs
489 489
  let p = Container.find new_pdx nl
490 490
      new_inst = Instance.setBoth inst new_pdx Node.noSecondary
491 491
  in do
492
    Instance.instMatchesPolicy inst (Node.iPolicy p)
492
    Instance.instMatchesPolicy inst (Node.iPolicy p) (Node.exclStorage p)
493 493
    new_p <- Node.addPri p inst
494 494
    let new_nl = Container.add new_pdx new_p nl
495 495
        new_score = compCV new_nl
......
503 503
      tgt_s = Container.find new_sdx nl
504 504
  in do
505 505
    Instance.instMatchesPolicy inst (Node.iPolicy tgt_p)
506
      (Node.exclStorage tgt_p)
506 507
    new_p <- Node.addPri tgt_p inst
507 508
    new_s <- Node.addSec tgt_s inst new_pdx
508 509
    let new_inst = Instance.setBoth inst new_pdx new_sdx
b/src/Ganeti/HTools/Instance.hs
59 59
  , mirrorType
60 60
  ) where
61 61

  
62
import Control.Monad (liftM2)
63

  
62 64
import Ganeti.BasicTypes
63 65
import qualified Ganeti.HTools.Types as T
64 66
import qualified Ganeti.HTools.Container as Container
......
278 280
-- | Checks if an instance is smaller/bigger than a given spec. Returns
279 281
-- OpGood for a correct spec, otherwise Bad one of the possible
280 282
-- failure modes.
281
instCompareISpec :: Ordering -> Instance-> T.ISpec -> T.OpResult ()
282
instCompareISpec which inst ispec
283
instCompareISpec :: Ordering -> Instance-> T.ISpec -> Bool -> T.OpResult ()
284
instCompareISpec which inst ispec exclstor
283 285
  | which == mem inst `compare` T.iSpecMemorySize ispec = Bad T.FailMem
284 286
  | which `elem` map ((`compare` T.iSpecDiskSize ispec) . dskSize)
285 287
    (disks inst) = Bad T.FailDisk
286 288
  | which == vcpus inst `compare` T.iSpecCpuCount ispec = Bad T.FailCPU
287
  | which == spindleUse inst `compare` T.iSpecSpindleUse ispec
289
  | exclstor &&
290
    case getTotalSpindles inst of
291
      Nothing -> True
292
      Just sp_sum -> which == sp_sum `compare` T.iSpecSpindleUse ispec
293
    = Bad T.FailSpindles
294
  | not exclstor && which == spindleUse inst `compare` T.iSpecSpindleUse ispec
288 295
    = Bad T.FailSpindles
289 296
  | diskTemplate inst /= T.DTDiskless &&
290 297
    which == length (disks inst) `compare` T.iSpecDiskCount ispec
......
292 299
  | otherwise = Ok ()
293 300

  
294 301
-- | Checks if an instance is smaller than a given spec.
295
instBelowISpec :: Instance -> T.ISpec -> T.OpResult ()
302
instBelowISpec :: Instance -> T.ISpec -> Bool -> T.OpResult ()
296 303
instBelowISpec = instCompareISpec GT
297 304

  
298 305
-- | Checks if an instance is bigger than a given spec.
299
instAboveISpec :: Instance -> T.ISpec -> T.OpResult ()
306
instAboveISpec :: Instance -> T.ISpec -> Bool -> T.OpResult ()
300 307
instAboveISpec = instCompareISpec LT
301 308

  
302 309
-- | Checks if an instance matches a min/max specs pair
303
instMatchesMinMaxSpecs :: Instance -> T.MinMaxISpecs -> T.OpResult ()
304
instMatchesMinMaxSpecs inst minmax = do
305
  instAboveISpec inst (T.minMaxISpecsMinSpec minmax)
306
  instBelowISpec inst (T.minMaxISpecsMaxSpec minmax)
310
instMatchesMinMaxSpecs :: Instance -> T.MinMaxISpecs -> Bool -> T.OpResult ()
311
instMatchesMinMaxSpecs inst minmax exclstor = do
312
  instAboveISpec inst (T.minMaxISpecsMinSpec minmax) exclstor
313
  instBelowISpec inst (T.minMaxISpecsMaxSpec minmax) exclstor
307 314

  
308 315
-- | Checks if an instance matches any specs of a policy
309
instMatchesSpecs :: Instance -> [T.MinMaxISpecs] -> T.OpResult ()
316
instMatchesSpecs :: Instance -> [T.MinMaxISpecs] -> Bool -> T.OpResult ()
310 317
 -- Return Ok for no constraints, though this should never happen
311
instMatchesSpecs _ [] = Ok ()
312
instMatchesSpecs inst minmaxes =
318
instMatchesSpecs _ [] _ = Ok ()
319
instMatchesSpecs inst minmaxes exclstor =
313 320
  -- The initial "Bad" should be always replaced by a real result
314 321
  foldr eithermatch (Bad T.FailInternal) minmaxes
315
  where eithermatch mm (Bad _) = instMatchesMinMaxSpecs inst mm
322
  where eithermatch mm (Bad _) = instMatchesMinMaxSpecs inst mm exclstor
316 323
        eithermatch _ y@(Ok ()) = y
317 324

  
318 325
-- | Checks if an instance matches a policy.
319
instMatchesPolicy :: Instance -> T.IPolicy -> T.OpResult ()
320
instMatchesPolicy inst ipol = do
321
  instMatchesSpecs inst $ T.iPolicyMinMaxISpecs ipol
326
instMatchesPolicy :: Instance -> T.IPolicy -> Bool -> T.OpResult ()
327
instMatchesPolicy inst ipol exclstor = do
328
  instMatchesSpecs inst (T.iPolicyMinMaxISpecs ipol) exclstor
322 329
  if diskTemplate inst `elem` T.iPolicyDiskTemplates ipol
323 330
    then Ok ()
324 331
    else Bad T.FailDisk
b/test/hs/Test/Ganeti/HTools/Cluster.hs
394 394
  forAll genOnlineNode $ \node ->
395 395
  forAll (choose (5, 20)) $ \count ->
396 396
  forAll (genInstanceSmallerThanNode node) $ \inst ->
397
  forAll (arbitrary `suchThat` (isBad .
398
                                Instance.instMatchesPolicy inst)) $ \ipol ->
397
  forAll (arbitrary `suchThat`
398
          (isBad . flip (Instance.instMatchesPolicy inst)
399
           (Node.exclStorage node))) $ \ipol ->
399 400
  let rqn = Instance.requiredNodes $ Instance.diskTemplate inst
400 401
      node' = Node.setPolicy ipol node
401 402
      nl = makeSmallCluster node' count
b/test/py/ganeti.cmdlib_unittest.py
827 827

  
828 828

  
829 829
class _FakeConfigForComputeIPolicyInstanceViolation:
830
  def __init__(self, be):
830
  def __init__(self, be, excl_stor):
831 831
    self.cluster = objects.Cluster(beparams={"default": be})
832
    self.excl_stor = excl_stor
832 833

  
833 834
  def GetClusterInfo(self):
834 835
    return self.cluster
835 836

  
837
  def GetNodeInfo(self, _):
838
    return {}
839

  
840
  def GetNdParams(self, _):
841
    return {
842
      constants.ND_EXCLUSIVE_STORAGE: self.excl_stor,
843
      }
844

  
836 845

  
837 846
class TestComputeIPolicyInstanceViolation(unittest.TestCase):
838 847
  def test(self):
......
841 850
      constants.BE_VCPUS: 2,
842 851
      constants.BE_SPINDLE_USE: 4,
843 852
      }
844
    disks = [objects.Disk(size=512)]
845
    cfg = _FakeConfigForComputeIPolicyInstanceViolation(beparams)
853
    disks = [objects.Disk(size=512, spindles=13)]
854
    cfg = _FakeConfigForComputeIPolicyInstanceViolation(beparams, False)
846 855
    instance = objects.Instance(beparams=beparams, disks=disks, nics=[],
847 856
                                disk_template=constants.DT_PLAIN)
848 857
    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 4,
......
855 864
    ret = common.ComputeIPolicyInstanceViolation(NotImplemented, instance2,
856 865
                                                 cfg, _compute_fn=stub)
857 866
    self.assertEqual(ret, [])
867
    cfg_es = _FakeConfigForComputeIPolicyInstanceViolation(beparams, True)
868
    stub_es = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 13,
869
                                               constants.DT_PLAIN)
870
    ret = common.ComputeIPolicyInstanceViolation(NotImplemented, instance,
871
                                                 cfg_es, _compute_fn=stub_es)
872
    self.assertEqual(ret, [])
873
    ret = common.ComputeIPolicyInstanceViolation(NotImplemented, instance2,
874
                                                 cfg_es, _compute_fn=stub_es)
875
    self.assertEqual(ret, [])
858 876

  
859 877

  
860 878
class TestComputeIPolicyInstanceSpecViolation(unittest.TestCase):

Also available in: Unified diff