+
+
+def _MaybeParseUnit(elements):
+ """Parses and returns an array of potential values with units.
+
+ """
+ parsed = {}
+ for k, v in elements.items():
+ if v == constants.VALUE_DEFAULT:
+ parsed[k] = v
+ else:
+ parsed[k] = utils.ParseUnit(v)
+ return parsed
+
+
+def _InitISpecsFromSplitOpts(ipolicy, ispecs_mem_size, ispecs_cpu_count,
+ ispecs_disk_count, ispecs_disk_size,
+ ispecs_nic_count, group_ipolicy, fill_all):
+ try:
+ if ispecs_mem_size:
+ ispecs_mem_size = _MaybeParseUnit(ispecs_mem_size)
+ if ispecs_disk_size:
+ ispecs_disk_size = _MaybeParseUnit(ispecs_disk_size)
+ except (TypeError, ValueError, errors.UnitParseError), err:
+ raise errors.OpPrereqError("Invalid disk (%s) or memory (%s) size"
+ " in policy: %s" %
+ (ispecs_disk_size, ispecs_mem_size, err),
+ errors.ECODE_INVAL)
+
+ # prepare ipolicy dict
+ ispecs_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 ispecs_transposed.values():
+ assert type(specs) is dict
+ utils.ForceDictType(specs, forced_type)
+
+ # then transpose
+ ispecs = {
+ constants.ISPECS_MIN: {},
+ constants.ISPECS_MAX: {},
+ constants.ISPECS_STD: {},
+ }
+ for (name, specs) in ispecs_transposed.iteritems():
+ assert name in constants.ISPECS_PARAMETERS
+ for key, val in specs.items(): # {min: .. ,max: .., std: ..}
+ assert key in ispecs
+ ispecs[key][name] = val
+ minmax_out = {}
+ for key in constants.ISPECS_MINMAX_KEYS:
+ if fill_all:
+ minmax_out[key] = \
+ objects.FillDict(constants.ISPECS_MINMAX_DEFAULTS[key], ispecs[key])
+ else:
+ minmax_out[key] = ispecs[key]
+ ipolicy[constants.ISPECS_MINMAX] = [minmax_out]
+ if fill_all:
+ ipolicy[constants.ISPECS_STD] = \
+ objects.FillDict(constants.IPOLICY_DEFAULTS[constants.ISPECS_STD],
+ ispecs[constants.ISPECS_STD])
+ else:
+ ipolicy[constants.ISPECS_STD] = ispecs[constants.ISPECS_STD]
+
+
+def _ParseSpecUnit(spec, keyname):
+ ret = spec.copy()
+ for k in [constants.ISPEC_DISK_SIZE, constants.ISPEC_MEM_SIZE]:
+ if k in ret:
+ try:
+ ret[k] = utils.ParseUnit(ret[k])
+ except (TypeError, ValueError, errors.UnitParseError), err:
+ raise errors.OpPrereqError(("Invalid parameter %s (%s) in %s instance"
+ " specs: %s" % (k, ret[k], keyname, err)),
+ errors.ECODE_INVAL)
+ return ret
+
+
+def _ParseISpec(spec, keyname, required):
+ ret = _ParseSpecUnit(spec, keyname)
+ utils.ForceDictType(ret, constants.ISPECS_PARAMETER_TYPES)
+ missing = constants.ISPECS_PARAMETERS - frozenset(ret.keys())
+ if required and missing:
+ raise errors.OpPrereqError("Missing parameters in ipolicy spec %s: %s" %
+ (keyname, utils.CommaJoin(missing)),
+ errors.ECODE_INVAL)
+ return ret
+
+
+def _GetISpecsInAllowedValues(minmax_ispecs, allowed_values):
+ ret = None
+ if (minmax_ispecs and allowed_values and len(minmax_ispecs) == 1 and
+ len(minmax_ispecs[0]) == 1):
+ for (key, spec) in minmax_ispecs[0].items():
+ # This loop is executed exactly once
+ if key in allowed_values and not spec:
+ ret = key
+ return ret
+
+
+def _InitISpecsFromFullOpts(ipolicy_out, minmax_ispecs, std_ispecs,
+ group_ipolicy, allowed_values):
+ found_allowed = _GetISpecsInAllowedValues(minmax_ispecs, allowed_values)
+ if found_allowed is not None:
+ ipolicy_out[constants.ISPECS_MINMAX] = found_allowed
+ elif minmax_ispecs is not None:
+ minmax_out = []
+ for mmpair in minmax_ispecs:
+ mmpair_out = {}
+ for (key, spec) in mmpair.items():
+ if key not in constants.ISPECS_MINMAX_KEYS:
+ msg = "Invalid key in bounds instance specifications: %s" % key
+ raise errors.OpPrereqError(msg, errors.ECODE_INVAL)
+ mmpair_out[key] = _ParseISpec(spec, key, True)
+ minmax_out.append(mmpair_out)
+ ipolicy_out[constants.ISPECS_MINMAX] = minmax_out
+ if std_ispecs is not None:
+ assert not group_ipolicy # This is not an option for gnt-group
+ ipolicy_out[constants.ISPECS_STD] = _ParseISpec(std_ispecs, "std", False)
+
+
+def CreateIPolicyFromOpts(ispecs_mem_size=None,
+ ispecs_cpu_count=None,
+ ispecs_disk_count=None,
+ ispecs_disk_size=None,
+ ispecs_nic_count=None,
+ minmax_ispecs=None,
+ std_ispecs=None,
+ ipolicy_disk_templates=None,
+ ipolicy_vcpu_ratio=None,
+ ipolicy_spindle_ratio=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
+
+ """
+ assert not (fill_all and allowed_values)
+
+ split_specs = (ispecs_mem_size or ispecs_cpu_count or ispecs_disk_count or
+ ispecs_disk_size or ispecs_nic_count)
+ if (split_specs and (minmax_ispecs is not None or std_ispecs is not None)):
+ raise errors.OpPrereqError("A --specs-xxx option cannot be specified"
+ " together with any --ipolicy-xxx-specs option",
+ errors.ECODE_INVAL)
+
+ ipolicy_out = objects.MakeEmptyIPolicy()
+ if split_specs:
+ assert fill_all
+ _InitISpecsFromSplitOpts(ipolicy_out, ispecs_mem_size, ispecs_cpu_count,
+ ispecs_disk_count, ispecs_disk_size,
+ ispecs_nic_count, group_ipolicy, fill_all)
+ elif (minmax_ispecs is not None or std_ispecs is not None):
+ _InitISpecsFromFullOpts(ipolicy_out, minmax_ispecs, std_ispecs,
+ group_ipolicy, allowed_values)
+
+ if ipolicy_disk_templates is not None:
+ if allowed_values and ipolicy_disk_templates in allowed_values:
+ ipolicy_out[constants.IPOLICY_DTS] = ipolicy_disk_templates
+ else:
+ ipolicy_out[constants.IPOLICY_DTS] = list(ipolicy_disk_templates)
+ if ipolicy_vcpu_ratio is not None:
+ ipolicy_out[constants.IPOLICY_VCPU_RATIO] = ipolicy_vcpu_ratio
+ if ipolicy_spindle_ratio is not None:
+ ipolicy_out[constants.IPOLICY_SPINDLE_RATIO] = ipolicy_spindle_ratio
+
+ assert not (frozenset(ipolicy_out.keys()) - constants.IPOLICY_ALL_KEYS)
+
+ if not group_ipolicy and fill_all:
+ ipolicy_out = objects.FillIPolicy(constants.IPOLICY_DEFAULTS, ipolicy_out)
+
+ return ipolicy_out
+
+
+def _SerializeGenericInfo(buf, data, level, afterkey=False):
+ """Formatting core of L{PrintGenericInfo}.
+
+ @param buf: (string) stream to accumulate the result into
+ @param data: data to format
+ @type level: int
+ @param level: depth in the data hierarchy, used for indenting
+ @type afterkey: bool
+ @param afterkey: True when we are in the middle of a line after a key (used
+ to properly add newlines or indentation)
+
+ """
+ baseind = " "
+ if isinstance(data, dict):
+ if not data:
+ buf.write("\n")
+ else:
+ if afterkey:
+ buf.write("\n")
+ doindent = True
+ else:
+ doindent = False
+ for key in sorted(data):
+ if doindent:
+ buf.write(baseind * level)
+ else:
+ doindent = True
+ buf.write(key)
+ buf.write(": ")
+ _SerializeGenericInfo(buf, data[key], level + 1, afterkey=True)
+ elif isinstance(data, list) and len(data) > 0 and isinstance(data[0], tuple):
+ # list of tuples (an ordered dictionary)
+ if afterkey:
+ buf.write("\n")
+ doindent = True
+ else:
+ doindent = False
+ for (key, val) in data:
+ if doindent:
+ buf.write(baseind * level)
+ else:
+ doindent = True
+ buf.write(key)
+ buf.write(": ")
+ _SerializeGenericInfo(buf, val, level + 1, afterkey=True)
+ elif isinstance(data, list):
+ if not data:
+ buf.write("\n")
+ else:
+ if afterkey:
+ buf.write("\n")
+ doindent = True
+ else:
+ doindent = False
+ for item in data:
+ if doindent:
+ buf.write(baseind * level)
+ else:
+ doindent = True
+ buf.write("-")
+ buf.write(baseind[1:])
+ _SerializeGenericInfo(buf, item, level + 1)
+ else:
+ # This branch should be only taken for strings, but it's practically
+ # impossible to guarantee that no other types are produced somewhere
+ buf.write(str(data))
+ buf.write("\n")
+
+
+def PrintGenericInfo(data):
+ """Print information formatted according to the hierarchy.
+
+ The output is a valid YAML string.
+
+ @param data: the data to print. It's a hierarchical structure whose elements
+ can be:
+ - dictionaries, where keys are strings and values are of any of the
+ types listed here
+ - lists of pairs (key, value), where key is a string and value is of
+ any of the types listed here; it's a way to encode ordered
+ dictionaries
+ - lists of any of the types listed here
+ - strings
+
+ """
+ buf = StringIO()
+ _SerializeGenericInfo(buf, data, 0)
+ ToStdout(buf.getvalue().rstrip("\n"))