commit 553cb5f7f776d48656005cea9778427e4e25d70f
Author: René Nussbaumer <rn@google.com>
Date:   Tue Mar 13 13:39:44 2012 +0100

    ipolicy: Keep track of spindle usage
    
    Signed-off-by: René Nussbaumer <rn@google.com>
    Reviewed-by: Iustin Pop <iustin@google.com>

diff --git a/doc/rapi.rst b/doc/rapi.rst
index baed7fe..a1dd48e 100644
--- a/doc/rapi.rst
+++ b/doc/rapi.rst
@@ -196,7 +196,8 @@ The instance policy specification is a dict with the following fields:
         constants.ISPEC_DISK_SIZE,
         constants.ISPEC_DISK_COUNT,
         constants.ISPEC_CPU_COUNT,
-        constants.ISPEC_NIC_COUNT]))
+        constants.ISPEC_NIC_COUNT,
+        constants.ISPEC_SPINDLE_USE]))
 
 .. |ispec-min| replace:: :pyeval:`constants.ISPECS_MIN`
 .. |ispec-max| replace:: :pyeval:`constants.ISPECS_MAX`
@@ -217,6 +218,10 @@ The instance policy specification is a dict with the following fields:
     The numbers of cpus used
   :pyeval:`constants.ISPEC_NIC_COUNT`
     The numbers of nics used
+  :pyeval:`constants.ISPEC_SPINDLE_USE`
+    The numbers of virtual disk spindles used by this instance. They are
+    not real, but useful for account the spindle usage on the residing
+    node.
 :pyeval:`constants.IPOLICY_DTS`
   A `list` of disk templates allowed for instances using this policy
 :pyeval:`constants.IPOLICY_VCPU_RATIO`
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 4c675c5..45a77dd 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -1093,7 +1093,7 @@ def _ComputeMinMaxSpec(name, ipolicy, value):
 
 
 def _ComputeIPolicySpecViolation(ipolicy, mem_size, cpu_count, disk_count,
-                                 nic_count, disk_sizes,
+                                 nic_count, disk_sizes, spindle_use,
                                  _compute_fn=_ComputeMinMaxSpec):
   """Verifies ipolicy against provided specs.
 
@@ -1109,6 +1109,8 @@ def _ComputeIPolicySpecViolation(ipolicy, mem_size, cpu_count, disk_count,
   @param nic_count: Number of nics used
   @type disk_sizes: list of ints
   @param disk_sizes: Disk sizes of used disk (len must match C{disk_count})
+  @type spindle_use: int
+  @param spindle_use: The number of spindles this instance uses
   @param _compute_fn: The compute function (unittest only)
   @return: A list of violations, or an empty list of no violations are found
 
@@ -1120,6 +1122,7 @@ def _ComputeIPolicySpecViolation(ipolicy, mem_size, cpu_count, disk_count,
     (constants.ISPEC_CPU_COUNT, cpu_count),
     (constants.ISPEC_DISK_COUNT, disk_count),
     (constants.ISPEC_NIC_COUNT, nic_count),
+    (constants.ISPEC_SPINDLE_USE, spindle_use),
     ] + map((lambda d: (constants.ISPEC_DISK_SIZE, d)), disk_sizes)
 
   return filter(None,
@@ -1141,12 +1144,13 @@ def _ComputeIPolicyInstanceViolation(ipolicy, instance,
   """
   mem_size = instance.beparams.get(constants.BE_MAXMEM, None)
   cpu_count = instance.beparams.get(constants.BE_VCPUS, None)
+  spindle_use = instance.beparams.get(constants.BE_SPINDLE_USAGE, None)
   disk_count = len(instance.disks)
   disk_sizes = [disk.size for disk in instance.disks]
   nic_count = len(instance.nics)
 
   return _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
-                     disk_sizes)
+                     disk_sizes, spindle_use)
 
 
 def _ComputeIPolicyInstanceSpecViolation(ipolicy, instance_spec,
@@ -1166,9 +1170,10 @@ def _ComputeIPolicyInstanceSpecViolation(ipolicy, instance_spec,
   disk_count = instance_spec.get(constants.ISPEC_DISK_COUNT, 0)
   disk_sizes = instance_spec.get(constants.ISPEC_DISK_SIZE, [])
   nic_count = instance_spec.get(constants.ISPEC_NIC_COUNT, 0)
+  spindle_use = instance_spec.get(constants.ISPEC_SPINDLE_USE, None)
 
   return _compute_fn(ipolicy, mem_size, cpu_count, disk_count, nic_count,
-                     disk_sizes)
+                     disk_sizes, spindle_use)
 
 
 def _ComputeIPolicyNodeViolation(ipolicy, instance, current_group,
@@ -9845,12 +9850,14 @@ class LUInstanceCreate(LogicalUnit):
     nodenames = [pnode.name] + self.secondaries
 
     # Verify instance specs
+    spindle_use = self.be_full.get(constants.BE_SPINDLE_USAGE, None)
     ispec = {
       constants.ISPEC_MEM_SIZE: self.be_full.get(constants.BE_MAXMEM, None),
       constants.ISPEC_CPU_COUNT: self.be_full.get(constants.BE_VCPUS, None),
       constants.ISPEC_DISK_COUNT: len(self.disks),
       constants.ISPEC_DISK_SIZE: [disk["size"] for disk in self.disks],
       constants.ISPEC_NIC_COUNT: len(self.nics),
+      constants.ISPEC_SPINDLE_USE: spindle_use,
       }
 
     group_info = self.cfg.GetNodeGroup(pnode.group)
diff --git a/lib/constants.py b/lib/constants.py
index aa93c65..63bceab 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -942,6 +942,7 @@ ISPEC_CPU_COUNT = "cpu-count"
 ISPEC_DISK_COUNT = "disk-count"
 ISPEC_DISK_SIZE = "disk-size"
 ISPEC_NIC_COUNT = "nic-count"
+ISPEC_SPINDLE_USE = "spindle-use"
 
 ISPECS_PARAMETER_TYPES = {
   ISPEC_MEM_SIZE: VTYPE_INT,
@@ -949,6 +950,7 @@ ISPECS_PARAMETER_TYPES = {
   ISPEC_DISK_COUNT: VTYPE_INT,
   ISPEC_DISK_SIZE: VTYPE_INT,
   ISPEC_NIC_COUNT: VTYPE_INT,
+  ISPEC_SPINDLE_USE: VTYPE_INT,
   }
 
 ISPECS_PARAMETERS = frozenset(ISPECS_PARAMETER_TYPES.keys())
@@ -1914,6 +1916,7 @@ IPOLICY_DEFAULTS = {
     ISPEC_DISK_COUNT: 1,
     ISPEC_DISK_SIZE: 1024,
     ISPEC_NIC_COUNT: 1,
+    ISPEC_SPINDLE_USE: 1,
     },
   ISPECS_MAX: {
     ISPEC_MEM_SIZE: 32768,
@@ -1921,6 +1924,7 @@ IPOLICY_DEFAULTS = {
     ISPEC_DISK_COUNT: MAX_DISKS,
     ISPEC_DISK_SIZE: 1024 * 1024,
     ISPEC_NIC_COUNT: MAX_NICS,
+    ISPEC_SPINDLE_USE: 12,
     },
   ISPECS_STD: {
     ISPEC_MEM_SIZE: 128,
@@ -1928,6 +1932,7 @@ IPOLICY_DEFAULTS = {
     ISPEC_DISK_COUNT: 1,
     ISPEC_DISK_SIZE: 1024,
     ISPEC_NIC_COUNT: 1,
+    ISPEC_SPINDLE_USE: 1,
     },
   IPOLICY_DTS: DISK_TEMPLATES,
   IPOLICY_VCPU_RATIO: 4.0,
diff --git a/test/ganeti.cmdlib_unittest.py b/test/ganeti.cmdlib_unittest.py
index df0ca4e..9b7efd6 100755
--- a/test/ganeti.cmdlib_unittest.py
+++ b/test/ganeti.cmdlib_unittest.py
@@ -645,36 +645,40 @@ class TestComputeIPolicySpecViolation(unittest.TestCase):
   def test(self):
     compute_fn = _ValidateComputeMinMaxSpec
     ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
-                                              [1024], _compute_fn=compute_fn)
+                                              [1024], 1, _compute_fn=compute_fn)
     self.assertEqual(ret, [])
 
   def testInvalidArguments(self):
     self.assertRaises(AssertionError, cmdlib._ComputeIPolicySpecViolation,
-                      NotImplemented, 1024, 1, 1, 1, [])
+                      NotImplemented, 1024, 1, 1, 1, [], 1)
 
   def testInvalidSpec(self):
-    spec = _SpecWrapper([None, False, "foo", None, "bar"])
+    spec = _SpecWrapper([None, False, "foo", None, "bar", None])
     compute_fn = spec.ComputeMinMaxSpec
     ret = cmdlib._ComputeIPolicySpecViolation(NotImplemented, 1024, 1, 1, 1,
-                                              [1024], _compute_fn=compute_fn)
+                                              [1024], 1, _compute_fn=compute_fn)
     self.assertEqual(ret, ["foo", "bar"])
     self.assertFalse(spec.spec)
 
 
 class _StubComputeIPolicySpecViolation:
-  def __init__(self, mem_size, cpu_count, disk_count, nic_count, disk_sizes):
+  def __init__(self, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
+               spindle_use):
     self.mem_size = mem_size
     self.cpu_count = cpu_count
     self.disk_count = disk_count
     self.nic_count = nic_count
     self.disk_sizes = disk_sizes
+    self.spindle_use = spindle_use
 
-  def __call__(self, _, mem_size, cpu_count, disk_count, nic_count, disk_sizes):
+  def __call__(self, _, mem_size, cpu_count, disk_count, nic_count, disk_sizes,
+               spindle_use):
     assert self.mem_size == mem_size
     assert self.cpu_count == cpu_count
     assert self.disk_count == disk_count
     assert self.nic_count == nic_count
     assert self.disk_sizes == disk_sizes
+    assert self.spindle_use == spindle_use
 
     return []
 
@@ -684,10 +688,11 @@ class TestComputeIPolicyInstanceViolation(unittest.TestCase):
     beparams = {
       constants.BE_MAXMEM: 2048,
       constants.BE_VCPUS: 2,
+      constants.BE_SPINDLE_USAGE: 4,
       }
     disks = [objects.Disk(size=512)]
     instance = objects.Instance(beparams=beparams, disks=disks, nics=[])
-    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512])
+    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 4)
     ret = cmdlib._ComputeIPolicyInstanceViolation(NotImplemented, instance,
                                                   _compute_fn=stub)
     self.assertEqual(ret, [])
@@ -701,8 +706,9 @@ class TestComputeIPolicyInstanceSpecViolation(unittest.TestCase):
       constants.ISPEC_DISK_COUNT: 1,
       constants.ISPEC_DISK_SIZE: [512],
       constants.ISPEC_NIC_COUNT: 0,
+      constants.ISPEC_SPINDLE_USE: 1,
       }
-    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512])
+    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 1)
     ret = cmdlib._ComputeIPolicyInstanceSpecViolation(NotImplemented, ispec,
                                                       _compute_fn=stub)
     self.assertEqual(ret, [])
