+ @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.
+
+ """
+ for param in constants.ISPECS_PARAMETERS:
+ InstancePolicy.CheckISpecSyntax(ipolicy, param, 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 CheckISpecSyntax(cls, ipolicy, name, check_std):
+ """Check the instance policy for validity on a given key.
+
+ We check if the instance policy makes sense for a given key, that is
+ if ipolicy[min][name] <= ipolicy[std][name] <= ipolicy[max][name].
+
+ @type ipolicy: dict
+ @param ipolicy: dictionary with min, max, std specs
+ @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
+ @raise errors.ConfigureError: when specs for given name are not valid
+
+ """
+ min_v = ipolicy[constants.ISPECS_MIN].get(name, 0)
+
+ if check_std:
+ std_v = ipolicy[constants.ISPECS_STD].get(name, min_v)
+ std_msg = std_v
+ else:
+ std_v = min_v
+ std_msg = "-"
+
+ max_v = ipolicy[constants.ISPECS_MAX].get(name, std_v)
+ err = ("Invalid specification of min/max/std values for %s: %s/%s/%s" %
+ (name,
+ ipolicy[constants.ISPECS_MIN].get(name, "-"),
+ ipolicy[constants.ISPECS_MAX].get(name, "-"),
+ std_msg))
+ if min_v > std_v or std_v > max_v:
+ raise errors.ConfigurationError(err)
+
+ @classmethod
+ def CheckDiskTemplates(cls, disk_templates):
+ """Checks the disk templates for validity.
+
+ """
+ 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))
+