+
+
+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 _InitIspecsFromOpts(ipolicy, ispecs_mem_size, ispecs_cpu_count,
+ ispecs_disk_count, ispecs_disk_size, ispecs_nic_count,
+ group_ipolicy, allowed_values):
+ 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():
+ utils.ForceDictType(specs, forced_type, allowed_values=allowed_values)
+
+ # 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
+ for key in constants.ISPECS_MINMAX_KEYS:
+ ipolicy[constants.ISPECS_MINMAX][key] = ispecs[key]
+ ipolicy[constants.ISPECS_STD] = ispecs[constants.ISPECS_STD]
+
+
+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,
+ 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
+
+
+ """
+
+ ipolicy_out = objects.MakeEmptyIPolicy()
+ _InitIspecsFromOpts(ipolicy_out, ispecs_mem_size, ispecs_cpu_count,
+ ispecs_disk_count, ispecs_disk_size, ispecs_nic_count,
+ group_ipolicy, allowed_values)
+
+ if ipolicy_disk_templates is not None:
+ 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"))