Merge branch 'stable-2.6'
[ganeti-local] / lib / objects.py
index ff921d6..5ba4a1b 100644 (file)
@@ -55,18 +55,6 @@ __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
 _TIMESTAMPS = ["ctime", "mtime"]
 _UUID = ["uuid"]
 
-# constants used to create InstancePolicy dictionary
-TISPECS_GROUP_TYPES = {
-  constants.ISPECS_MIN: constants.VTYPE_INT,
-  constants.ISPECS_MAX: constants.VTYPE_INT,
-  }
-
-TISPECS_CLUSTER_TYPES = {
-  constants.ISPECS_MIN: constants.VTYPE_INT,
-  constants.ISPECS_MAX: constants.VTYPE_INT,
-  constants.ISPECS_STD: constants.VTYPE_INT,
-  }
-
 
 def FillDict(defaults_dict, custom_dict, skip_keys=None):
   """Basic function to apply settings on top a default dict.
@@ -105,10 +93,26 @@ def FillIPolicy(default_ipolicy, custom_ipolicy, skip_keys=None):
   # list items
   for key in [constants.IPOLICY_DTS]:
     ret_dict[key] = list(custom_ipolicy.get(key, default_ipolicy[key]))
+  # other items which we know we can directly copy (immutables)
+  for key in constants.IPOLICY_PARAMETERS:
+    ret_dict[key] = custom_ipolicy.get(key, default_ipolicy[key])
 
   return ret_dict
 
 
+def FillDiskParams(default_dparams, custom_dparams, skip_keys=None):
+  """Fills the disk parameter defaults.
+
+  @see: L{FillDict} for parameters and return value
+
+  """
+  assert frozenset(default_dparams.keys()) == constants.DISK_TEMPLATES
+
+  return dict((dt, FillDict(default_dparams[dt], custom_dparams.get(dt, {}),
+                             skip_keys=skip_keys))
+              for dt in constants.DISK_TEMPLATES)
+
+
 def UpgradeGroupedParams(target, defaults):
   """Update all groups for the target parameter.
 
@@ -146,26 +150,32 @@ def UpgradeDiskParams(diskparams):
   @type diskparams: dict
   @param diskparams: disk parameters to upgrade
   @rtype: dict
-  @return: the upgraded disk parameters dit
+  @return: the upgraded disk parameters dict
 
   """
-  result = dict()
-  if diskparams is None:
-    result = constants.DISK_DT_DEFAULTS.copy()
+  if not diskparams:
+    result = {}
   else:
-    # Update the disk parameter values for each disk template.
-    # The code iterates over constants.DISK_TEMPLATES because new templates
-    # might have been added.
-    for template in constants.DISK_TEMPLATES:
-      if template not in diskparams:
-        result[template] = constants.DISK_DT_DEFAULTS[template].copy()
-      else:
-        result[template] = FillDict(constants.DISK_DT_DEFAULTS[template],
-                                    diskparams[template])
+    result = FillDiskParams(constants.DISK_DT_DEFAULTS, diskparams)
 
   return result
 
 
+def UpgradeNDParams(ndparams):
+  """Upgrade ndparams structure.
+
+  @type ndparams: dict
+  @param ndparams: disk parameters to upgrade
+  @rtype: dict
+  @return: the upgraded node parameters dict
+
+  """
+  if ndparams is None:
+    ndparams = {}
+
+  return FillDict(constants.NDC_DEFAULTS, ndparams)
+
+
 def MakeEmptyIPolicy():
   """Create empty IPolicy dictionary.
 
@@ -177,58 +187,6 @@ def MakeEmptyIPolicy():
     ])
 
 
-def CreateIPolicyFromOpts(ispecs_mem_size=None,
-                          ispecs_cpu_count=None,
-                          ispecs_disk_count=None,
-                          ispecs_disk_size=None,
-                          ispecs_nic_count=None,
-                          ipolicy_disk_templates=None,
-                          group_ipolicy=False,
-                          allowed_values=None,
-                          fill_all=False):
-  """Creation of instance policy based on command line options.
-
-  @param fill_all: whether for cluster policies we should ensure that
-    all values are filled
-
-
-  """
-  # prepare ipolicy dict
-  ipolicy_transposed = {
-    constants.ISPEC_MEM_SIZE: ispecs_mem_size,
-    constants.ISPEC_CPU_COUNT: ispecs_cpu_count,
-    constants.ISPEC_DISK_COUNT: ispecs_disk_count,
-    constants.ISPEC_DISK_SIZE: ispecs_disk_size,
-    constants.ISPEC_NIC_COUNT: ispecs_nic_count,
-    }
-
-  # first, check that the values given are correct
-  if group_ipolicy:
-    forced_type = TISPECS_GROUP_TYPES
-  else:
-    forced_type = TISPECS_CLUSTER_TYPES
-
-  for specs in ipolicy_transposed.values():
-    utils.ForceDictType(specs, forced_type, allowed_values=allowed_values)
-
-  # then transpose
-  ipolicy_out = MakeEmptyIPolicy()
-  for name, specs in ipolicy_transposed.iteritems():
-    assert name in constants.ISPECS_PARAMETERS
-    for key, val in specs.items(): # {min: .. ,max: .., std: ..}
-      ipolicy_out[key][name] = val
-
-  # no filldict for lists
-  if not group_ipolicy and fill_all and ipolicy_disk_templates is None:
-    ipolicy_disk_templates = constants.DISK_TEMPLATES
-  if ipolicy_disk_templates is not None:
-    ipolicy_out[constants.IPOLICY_DTS] = list(ipolicy_disk_templates)
-
-  assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
-
-  return ipolicy_out
-
-
 class ConfigObject(object):
   """A generic config object.
 
@@ -270,6 +228,9 @@ class ConfigObject(object):
       slots.extend(getattr(parent, "__slots__", []))
     return slots
 
+  #: Public getter for the defined slots
+  GetAllSlots = _all_slots
+
   def ToDict(self):
     """Convert to a dict holding only standard python types.
 
@@ -890,6 +851,94 @@ class Disk(ConfigObject):
                              self.params)
     # add here config upgrade for this disk
 
+  @staticmethod
+  def ComputeLDParams(disk_template, disk_params):
+    """Computes Logical Disk parameters from Disk Template parameters.
+
+    @type disk_template: string
+    @param disk_template: disk template, one of L{constants.DISK_TEMPLATES}
+    @type disk_params: dict
+    @param disk_params: disk template parameters;
+                        dict(template_name -> parameters
+    @rtype: list(dict)
+    @return: a list of dicts, one for each node of the disk hierarchy. Each dict
+      contains the LD parameters of the node. The tree is flattened in-order.
+
+    """
+    if disk_template not in constants.DISK_TEMPLATES:
+      raise errors.ProgrammerError("Unknown disk template %s" % disk_template)
+
+    assert disk_template in disk_params
+
+    result = list()
+    dt_params = disk_params[disk_template]
+    if disk_template == constants.DT_DRBD8:
+      drbd_params = {
+        constants.LDP_RESYNC_RATE: dt_params[constants.DRBD_RESYNC_RATE],
+        constants.LDP_BARRIERS: dt_params[constants.DRBD_DISK_BARRIERS],
+        constants.LDP_NO_META_FLUSH: dt_params[constants.DRBD_META_BARRIERS],
+        constants.LDP_DEFAULT_METAVG: dt_params[constants.DRBD_DEFAULT_METAVG],
+        constants.LDP_DISK_CUSTOM: dt_params[constants.DRBD_DISK_CUSTOM],
+        constants.LDP_NET_CUSTOM: dt_params[constants.DRBD_NET_CUSTOM],
+        constants.LDP_DYNAMIC_RESYNC: dt_params[constants.DRBD_DYNAMIC_RESYNC],
+        constants.LDP_PLAN_AHEAD: dt_params[constants.DRBD_PLAN_AHEAD],
+        constants.LDP_FILL_TARGET: dt_params[constants.DRBD_FILL_TARGET],
+        constants.LDP_DELAY_TARGET: dt_params[constants.DRBD_DELAY_TARGET],
+        constants.LDP_MAX_RATE: dt_params[constants.DRBD_MAX_RATE],
+        constants.LDP_MIN_RATE: dt_params[constants.DRBD_MIN_RATE],
+        }
+
+      drbd_params = \
+        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_DRBD8],
+                 drbd_params)
+
+      result.append(drbd_params)
+
+      # data LV
+      data_params = {
+        constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES],
+        }
+      data_params = \
+        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
+                 data_params)
+      result.append(data_params)
+
+      # metadata LV
+      meta_params = {
+        constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES],
+        }
+      meta_params = \
+        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
+                 meta_params)
+      result.append(meta_params)
+
+    elif (disk_template == constants.DT_FILE or
+          disk_template == constants.DT_SHARED_FILE):
+      result.append(constants.DISK_LD_DEFAULTS[constants.LD_FILE])
+
+    elif disk_template == constants.DT_PLAIN:
+      params = {
+        constants.LDP_STRIPES: dt_params[constants.LV_STRIPES],
+        }
+      params = \
+        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV],
+                 params)
+      result.append(params)
+
+    elif disk_template == constants.DT_BLOCK:
+      result.append(constants.DISK_LD_DEFAULTS[constants.LD_BLOCKDEV])
+
+    elif disk_template == constants.DT_RBD:
+      params = {
+        constants.LDP_POOL: dt_params[constants.RBD_POOL]
+        }
+      params = \
+        FillDict(constants.DISK_LD_DEFAULTS[constants.LD_RBD],
+                 params)
+      result.append(params)
+
+    return result
+
 
 class InstancePolicy(ConfigObject):
   """Config object representing instance policy limits dictionary.
@@ -908,6 +957,9 @@ class InstancePolicy(ConfigObject):
       InstancePolicy.CheckISpecSyntax(ipolicy, param)
     if constants.IPOLICY_DTS in ipolicy:
       InstancePolicy.CheckDiskTemplates(ipolicy[constants.IPOLICY_DTS])
+    for key in constants.IPOLICY_PARAMETERS:
+      if key in ipolicy:
+        InstancePolicy.CheckParameter(key, ipolicy[key])
     wrong_keys = frozenset(ipolicy.keys()) - constants.IPOLICY_ALL_KEYS
     if wrong_keys:
       raise errors.ConfigurationError("Invalid keys in ipolicy: %s" %
@@ -948,6 +1000,19 @@ class InstancePolicy(ConfigObject):
       raise errors.ConfigurationError("Invalid disk template(s) %s" %
                                       utils.CommaJoin(wrong))
 
+  @classmethod
+  def CheckParameter(cls, key, value):
+    """Checks a parameter.
+
+    Currently we expect all parameters to be float values.
+
+    """
+    try:
+      float(value)
+    except (TypeError, ValueError), err:
+      raise errors.ConfigurationError("Invalid value for key" " '%s':"
+                                      " '%s', error: %s" % (key, value, err))
+
 
 class Instance(TaggableObject):
   """Config object representing an instance."""
@@ -1360,7 +1425,8 @@ class NodeGroup(TaggableObject):
     if self.mtime is None:
       self.mtime = time.time()
 
-    self.diskparams = UpgradeDiskParams(self.diskparams)
+    if self.diskparams is None:
+      self.diskparams = {}
     if self.ipolicy is None:
       self.ipolicy = MakeEmptyIPolicy()
 
@@ -1451,8 +1517,7 @@ class Cluster(TaggableObject):
     if self.osparams is None:
       self.osparams = {}
 
-    if self.ndparams is None:
-      self.ndparams = constants.NDC_DEFAULTS
+    self.ndparams = UpgradeNDParams(self.ndparams)
 
     self.beparams = UpgradeGroupedParams(self.beparams,
                                          constants.BEC_DEFAULTS)
@@ -1525,7 +1590,10 @@ class Cluster(TaggableObject):
     if self.use_external_mip_script is None:
       self.use_external_mip_script = False
 
-    self.diskparams = UpgradeDiskParams(self.diskparams)
+    if self.diskparams:
+      self.diskparams = UpgradeDiskParams(self.diskparams)
+    else:
+      self.diskparams = constants.DISK_DT_DEFAULTS.copy()
 
     # instance policy added before 2.6
     if self.ipolicy is None:
@@ -1563,6 +1631,15 @@ class Cluster(TaggableObject):
       obj.tcpudp_port_pool = set(obj.tcpudp_port_pool)
     return obj
 
+  def SimpleFillDP(self, diskparams):
+    """Fill a given diskparams dict with cluster defaults.
+
+    @param diskparams: The diskparams
+    @return: The defaults dict
+
+    """
+    return FillDiskParams(self.diskparams, diskparams)
+
   def GetHVDefaults(self, hypervisor, os_name=None, skip_keys=None):
     """Get the default hypervisor parameters for the cluster.
 
@@ -1855,17 +1932,6 @@ class _QueryResponseBase(ConfigObject):
     return obj
 
 
-class QueryRequest(ConfigObject):
-  """Object holding a query request.
-
-  """
-  __slots__ = [
-    "what",
-    "fields",
-    "qfilter",
-    ]
-
-
 class QueryResponse(_QueryResponseBase):
   """Object holding the response to a query.