hypervisors: add hvparams to GetNodeInfo
[ganeti-local] / lib / objects.py
index 282aece..f523f2a 100644 (file)
@@ -512,8 +512,9 @@ class NIC(ConfigObject):
 
 class Disk(ConfigObject):
   """Config object representing a block device."""
-  __slots__ = ["name", "dev_type", "logical_id", "physical_id",
-               "children", "iv_name", "size", "mode", "params"] + _UUID
+  __slots__ = (["name", "dev_type", "logical_id", "physical_id",
+                "children", "iv_name", "size", "mode", "params", "spindles"] +
+               _UUID)
 
   def CreateOnSecondary(self):
     """Test if this device needs to be created on a secondary node."""
@@ -674,8 +675,8 @@ class Disk(ConfigObject):
       raise errors.ProgrammerError("Disk.RecordGrow called for unsupported"
                                    " disk type %s" % self.dev_type)
 
-  def Update(self, size=None, mode=None):
-    """Apply changes to size and mode.
+  def Update(self, size=None, mode=None, spindles=None):
+    """Apply changes to size, spindles and mode.
 
     """
     if self.dev_type == constants.LD_DRBD8:
@@ -688,6 +689,8 @@ class Disk(ConfigObject):
       self.size = size
     if mode is not None:
       self.mode = mode
+    if spindles is not None:
+      self.spindles = spindles
 
   def UnsetSize(self):
     """Sets recursively the size to zero for the disk and its children.
@@ -804,6 +807,8 @@ class Disk(ConfigObject):
       val += ", not visible"
     else:
       val += ", visible as /dev/%s" % self.iv_name
+    if self.spindles is not None:
+      val += ", spindles=%s" % self.spindles
     if isinstance(self.size, int):
       val += ", size=%dm)>" % self.size
     else:
@@ -955,19 +960,29 @@ class InstancePolicy(ConfigObject):
     if check_std and constants.ISPECS_STD not in ipolicy:
       msg = "Missing key in ipolicy: %s" % constants.ISPECS_STD
       raise errors.ConfigurationError(msg)
-    minmaxspecs = ipolicy[constants.ISPECS_MINMAX]
     stdspec = ipolicy.get(constants.ISPECS_STD)
-    missing = constants.ISPECS_MINMAX_KEYS - frozenset(minmaxspecs.keys())
-    if missing:
-      msg = "Missing instance specification: %s" % utils.CommaJoin(missing)
-      raise errors.ConfigurationError(msg)
-    for (key, spec) in minmaxspecs.items():
-      InstancePolicy._CheckIncompleteSpec(spec, key)
     if check_std:
       InstancePolicy._CheckIncompleteSpec(stdspec, constants.ISPECS_STD)
-    for param in constants.ISPECS_PARAMETERS:
-      InstancePolicy._CheckISpecParamSyntax(minmaxspecs, stdspec, param,
-                                            check_std)
+
+    if not ipolicy[constants.ISPECS_MINMAX]:
+      raise errors.ConfigurationError("Empty minmax specifications")
+    std_is_good = False
+    for minmaxspecs in ipolicy[constants.ISPECS_MINMAX]:
+      missing = constants.ISPECS_MINMAX_KEYS - frozenset(minmaxspecs.keys())
+      if missing:
+        msg = "Missing instance specification: %s" % utils.CommaJoin(missing)
+        raise errors.ConfigurationError(msg)
+      for (key, spec) in minmaxspecs.items():
+        InstancePolicy._CheckIncompleteSpec(spec, key)
+
+      spec_std_ok = True
+      for param in constants.ISPECS_PARAMETERS:
+        par_std_ok = InstancePolicy._CheckISpecParamSyntax(minmaxspecs, stdspec,
+                                                           param, check_std)
+        spec_std_ok = spec_std_ok and par_std_ok
+      std_is_good = std_is_good or spec_std_ok
+    if not std_is_good:
+      raise errors.ConfigurationError("Invalid std specifications")
 
   @classmethod
   def _CheckISpecParamSyntax(cls, minmaxspecs, stdspec, name, check_std):
@@ -984,26 +999,27 @@ class InstancePolicy(ConfigObject):
     @param name: what are the limits for
     @type check_std: bool
     @param check_std: Whether to check std value or just assume compliance
-    @raise errors.ConfigurationError: when specs for the given name are not
-        valid
+    @rtype: bool
+    @return: C{True} when specs are valid, C{False} when standard spec for the
+        given name is not valid
+    @raise errors.ConfigurationError: when min/max specs for the given name
+        are not valid
 
     """
     minspec = minmaxspecs[constants.ISPECS_MIN]
     maxspec = minmaxspecs[constants.ISPECS_MAX]
     min_v = minspec[name]
+    max_v = maxspec[name]
 
-    if check_std:
+    if min_v > max_v:
+      err = ("Invalid specification of min/max values for %s: %s/%s" %
+             (name, min_v, max_v))
+      raise errors.ConfigurationError(err)
+    elif check_std:
       std_v = stdspec.get(name, min_v)
-      std_msg = std_v
+      return std_v >= min_v and std_v <= max_v
     else:
-      std_v = min_v
-      std_msg = "-"
-
-    max_v = maxspec[name]
-    if min_v > std_v or std_v > max_v:
-      err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
-             (name, min_v, max_v, std_msg))
-      raise errors.ConfigurationError(err)
+      return True
 
   @classmethod
   def CheckDiskTemplates(cls, disk_templates):
@@ -1046,6 +1062,7 @@ class Instance(TaggableObject):
     "nics",
     "disks",
     "disk_template",
+    "disks_active",
     "network_port",
     "serial_no",
     ] + _TIMESTAMPS + _UUID
@@ -1211,6 +1228,8 @@ class Instance(TaggableObject):
     if self.osparams is None:
       self.osparams = {}
     UpgradeBeParams(self.beparams)
+    if self.disks_active is None:
+      self.disks_active = self.admin_state == constants.ADMINST_UP
 
 
 class OS(ConfigObject):