+ # If the file driver is empty, fill it up with the default value
+ if self.dev_type == constants.LD_FILE and self.physical_id[0] is None:
+ self.physical_id[0] = constants.FD_DEFAULT
+
+ @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:
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_DRBD8], {
+ 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],
+ }))
+
+ # data LV
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
+ constants.LDP_STRIPES: dt_params[constants.DRBD_DATA_STRIPES],
+ }))
+
+ # metadata LV
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
+ constants.LDP_STRIPES: dt_params[constants.DRBD_META_STRIPES],
+ }))
+
+ elif disk_template in (constants.DT_FILE, constants.DT_SHARED_FILE):
+ result.append(constants.DISK_LD_DEFAULTS[constants.LD_FILE])
+
+ elif disk_template == constants.DT_PLAIN:
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_LV], {
+ constants.LDP_STRIPES: dt_params[constants.LV_STRIPES],
+ }))
+
+ elif disk_template == constants.DT_BLOCK:
+ result.append(constants.DISK_LD_DEFAULTS[constants.LD_BLOCKDEV])
+
+ elif disk_template == constants.DT_RBD:
+ result.append(FillDict(constants.DISK_LD_DEFAULTS[constants.LD_RBD], {
+ constants.LDP_POOL: dt_params[constants.RBD_POOL],
+ }))
+
+ elif disk_template == constants.DT_EXT:
+ result.append(constants.DISK_LD_DEFAULTS[constants.LD_EXT])
+
+ return result
+
+
+class InstancePolicy(ConfigObject):
+ """Config object representing instance policy limits dictionary.
+
+ Note that this object is not actually used in the config, it's just
+ used as a placeholder for a few functions.
+
+ """
+ @classmethod
+ def CheckParameterSyntax(cls, ipolicy, check_std):
+ """ Check the instance policy for validity.
+
+ @type ipolicy: dict
+ @param ipolicy: dictionary with min/max/std specs and policies
+ @type check_std: bool
+ @param check_std: Whether to check std value or just assume compliance
+ @raise errors.ConfigurationError: when the policy is not legal
+
+ """
+ InstancePolicy.CheckISpecSyntax(ipolicy, check_std)
+ 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" %
+ utils.CommaJoin(wrong_keys))
+
+ @classmethod
+ def _CheckIncompleteSpec(cls, spec, keyname):
+ missing_params = constants.ISPECS_PARAMETERS - frozenset(spec.keys())
+ if missing_params:
+ msg = ("Missing instance specs parameters for %s: %s" %
+ (keyname, utils.CommaJoin(missing_params)))
+ raise errors.ConfigurationError(msg)
+
+ @classmethod
+ def CheckISpecSyntax(cls, ipolicy, check_std):
+ """Check the instance policy specs for validity.
+
+ @type ipolicy: dict
+ @param ipolicy: dictionary with min/max/std specs
+ @type check_std: bool
+ @param check_std: Whether to check std value or just assume compliance
+ @raise errors.ConfigurationError: when specs are not valid
+
+ """
+ if constants.ISPECS_MINMAX not in ipolicy:
+ # Nothing to check
+ return
+
+ if check_std and constants.ISPECS_STD not in ipolicy:
+ msg = "Missing key in ipolicy: %s" % constants.ISPECS_STD
+ raise errors.ConfigurationError(msg)
+ stdspec = ipolicy.get(constants.ISPECS_STD)
+ if check_std:
+ InstancePolicy._CheckIncompleteSpec(stdspec, constants.ISPECS_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):
+ """Check the instance policy specs for validity on a given key.
+
+ We check if the instance specs makes sense for a given key, that is
+ if minmaxspecs[min][name] <= stdspec[name] <= minmaxspec[max][name].
+
+ @type minmaxspecs: dict
+ @param minmaxspecs: dictionary with min and max instance spec
+ @type stdspec: dict
+ @param stdspec: dictionary with standard instance spec
+ @type name: string
+ @param name: what are the limits for
+ @type check_std: bool
+ @param check_std: Whether to check std value or just assume compliance
+ @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 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)
+ return std_v >= min_v and std_v <= max_v
+ else:
+ return True
+
+ @classmethod
+ def CheckDiskTemplates(cls, disk_templates):
+ """Checks the disk templates for validity.
+
+ """
+ if not disk_templates:
+ raise errors.ConfigurationError("Instance policy must contain" +
+ " at least one disk template")
+ wrong = frozenset(disk_templates).difference(constants.DISK_TEMPLATES)
+ if wrong:
+ 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))
+