"GLOBAL_FILEDIR_OPT",
"HID_OS_OPT",
"GLOBAL_SHARED_FILEDIR_OPT",
+ "HOTPLUG_OPT",
"HVLIST_OPT",
"HVOPTS_OPT",
"HYPERVISOR_OPT",
"IGNORE_REMOVE_FAILURES_OPT",
"IGNORE_SECONDARIES_OPT",
"IGNORE_SIZE_OPT",
+ "INCLUDEDEFAULTS_OPT",
"INTERVAL_OPT",
"MAC_PREFIX_OPT",
"MAINTAIN_NODE_HEALTH_OPT",
"MASTER_NETMASK_OPT",
"MC_OPT",
"MIGRATION_MODE_OPT",
+ "MODIFY_ETCHOSTS_OPT",
"NET_OPT",
"NETWORK_OPT",
"NETWORK6_OPT",
"SPECS_DISK_SIZE_OPT",
"SPECS_MEM_SIZE_OPT",
"SPECS_NIC_COUNT_OPT",
+ "SPLIT_ISPECS_OPTS",
"IPOLICY_STD_SPECS_OPT",
"IPOLICY_DISK_TEMPLATES",
"IPOLICY_VCPU_RATIO",
"FormatQueryResult",
"FormatParamsDictInfo",
"FormatPolicyInfo",
+ "PrintIPolicyCommand",
"PrintGenericInfo",
"GenerateTable",
"AskUser",
return retval
-def check_list_ident_key_val(_, opt, value):
- """Custom parser for "ident:key=val,key=val/ident:key=val" options.
+def check_multilist_ident_key_val(_, opt, value):
+ """Custom parser for "ident:key=val,key=val/ident:key=val//ident:.." options.
@rtype: list of dictionary
- @return: {ident: {key: val, key: val}, ident: {key: val}}
+ @return: [{ident: {key: val, key: val}, ident: {key: val}}, {ident:..}]
"""
- return _SplitListKeyVal(opt, value)
+ retval = []
+ for line in value.split("//"):
+ retval.append(_SplitListKeyVal(opt, line))
+ return retval
def check_bool(option, opt, value): # pylint: disable=W0613
"completion_suggest",
]
TYPES = Option.TYPES + (
- "listidentkeyval",
+ "multilistidentkeyval",
"identkeyval",
"keyval",
"unit",
"maybefloat",
)
TYPE_CHECKER = Option.TYPE_CHECKER.copy()
- TYPE_CHECKER["listidentkeyval"] = check_list_ident_key_val
+ TYPE_CHECKER["multilistidentkeyval"] = check_multilist_ident_key_val
TYPE_CHECKER["identkeyval"] = check_ident_key_val
TYPE_CHECKER["keyval"] = check_key_val
TYPE_CHECKER["unit"] = check_unit
FILESTORE_DRIVER_OPT = cli_option("--file-driver", dest="file_driver",
help="Driver to use for image files",
- default="loop", metavar="<DRIVER>",
+ default=None, metavar="<DRIVER>",
choices=list(constants.FILE_DRIVER))
IALLOCATOR_OPT = cli_option("-I", "--iallocator", metavar="<NAME>",
IPOLICY_BOUNDS_SPECS_STR = "--ipolicy-bounds-specs"
IPOLICY_BOUNDS_SPECS_OPT = cli_option(IPOLICY_BOUNDS_SPECS_STR,
dest="ipolicy_bounds_specs",
- type="listidentkeyval", default=None,
+ type="multilistidentkeyval", default=None,
help="Complete instance specs limits")
IPOLICY_STD_SPECS_STR = "--ipolicy-std-specs"
CLEANUP_OPT = cli_option("--cleanup", dest="cleanup",
default=False, action="store_true",
- help="Instead of performing the migration, try to"
- " recover from a failed cleanup. This is safe"
+ help="Instead of performing the migration/failover,"
+ " try to recover from a failed cleanup. This is safe"
" to run even if the instance is healthy, but it"
" will create extra replication traffic and "
" disrupt briefly the replication (like during the"
- " migration")
+ " migration/failover")
STATIC_OPT = cli_option("-s", "--static", dest="static",
action="store_true", default=False,
help="Don't modify %s" % pathutils.ETC_HOSTS,
action="store_false", default=True)
+MODIFY_ETCHOSTS_OPT = \
+ cli_option("--modify-etc-hosts", dest="modify_etc_hosts", metavar=_YORNO,
+ default=None, type="bool",
+ help="Defines whether the cluster should autonomously modify"
+ " and keep in sync the /etc/hosts file of the nodes")
+
NOMODIFY_SSH_SETUP_OPT = cli_option("--no-ssh-init", dest="modify_ssh_setup",
help="Don't initialize SSH keys",
action="store_false", default=True)
action="store_false",
help="Don't check for conflicting IPs")
+INCLUDEDEFAULTS_OPT = cli_option("--include-defaults", dest="include_defaults",
+ default=False, action="store_true",
+ help="Include default values")
+
+HOTPLUG_OPT = cli_option("--hotplug", dest="hotplug",
+ action="store_true", default=False,
+ help="Try to hotplug device")
+
#: Options provided by all commands
COMMON_OPTS = [DEBUG_OPT, REASON_OPT]
# common instance policy options
INSTANCE_POLICY_OPTS = [
+ IPOLICY_BOUNDS_SPECS_OPT,
+ IPOLICY_DISK_TEMPLATES,
+ IPOLICY_VCPU_RATIO,
+ IPOLICY_SPINDLE_RATIO,
+ ]
+
+# instance policy split specs options
+SPLIT_ISPECS_OPTS = [
SPECS_CPU_COUNT_OPT,
SPECS_DISK_COUNT_OPT,
SPECS_DISK_SIZE_OPT,
SPECS_MEM_SIZE_OPT,
SPECS_NIC_COUNT_OPT,
- IPOLICY_BOUNDS_SPECS_OPT,
- IPOLICY_DISK_TEMPLATES,
- IPOLICY_VCPU_RATIO,
- IPOLICY_SPINDLE_RATIO,
]
if iscluster:
eff_ipolicy = custom_ipolicy
+ minmax_out = []
custom_minmax = custom_ipolicy.get(constants.ISPECS_MINMAX)
- ret = [
- (key,
- FormatParamsDictInfo(custom_minmax.get(key, {}),
- eff_ipolicy[constants.ISPECS_MINMAX][key]))
- for key in constants.ISPECS_MINMAX_KEYS
- ]
+ if custom_minmax:
+ for (k, minmax) in enumerate(custom_minmax):
+ minmax_out.append([
+ ("%s/%s" % (key, k),
+ FormatParamsDictInfo(minmax[key], minmax[key]))
+ for key in constants.ISPECS_MINMAX_KEYS
+ ])
+ else:
+ for (k, minmax) in enumerate(eff_ipolicy[constants.ISPECS_MINMAX]):
+ minmax_out.append([
+ ("%s/%s" % (key, k),
+ FormatParamsDictInfo({}, minmax[key]))
+ for key in constants.ISPECS_MINMAX_KEYS
+ ])
+ ret = [("bounds specs", minmax_out)]
+
if iscluster:
stdspecs = custom_ipolicy[constants.ISPECS_STD]
ret.append(
)
ret.append(
- ("enabled disk templates",
+ ("allowed disk templates",
_FormatListInfoDefault(custom_ipolicy.get(constants.IPOLICY_DTS),
eff_ipolicy[constants.IPOLICY_DTS]))
)
return ret
+def _PrintSpecsParameters(buf, specs):
+ values = ("%s=%s" % (par, val) for (par, val) in sorted(specs.items()))
+ buf.write(",".join(values))
+
+
+def PrintIPolicyCommand(buf, ipolicy, isgroup):
+ """Print the command option used to generate the given instance policy.
+
+ Currently only the parts dealing with specs are supported.
+
+ @type buf: StringIO
+ @param buf: stream to write into
+ @type ipolicy: dict
+ @param ipolicy: instance policy
+ @type isgroup: bool
+ @param isgroup: whether the policy is at group level
+
+ """
+ if not isgroup:
+ stdspecs = ipolicy.get("std")
+ if stdspecs:
+ buf.write(" %s " % IPOLICY_STD_SPECS_STR)
+ _PrintSpecsParameters(buf, stdspecs)
+ minmaxes = ipolicy.get("minmax", [])
+ first = True
+ for minmax in minmaxes:
+ minspecs = minmax.get("min")
+ maxspecs = minmax.get("max")
+ if minspecs and maxspecs:
+ if first:
+ buf.write(" %s " % IPOLICY_BOUNDS_SPECS_STR)
+ first = False
+ else:
+ buf.write("//")
+ buf.write("min:")
+ _PrintSpecsParameters(buf, minspecs)
+ buf.write("/max:")
+ _PrintSpecsParameters(buf, maxspecs)
+
+
def ConfirmOperation(names, list_type, text, extra=""):
"""Ask the user to confirm an operation on a list of list_type.
def _InitISpecsFromSplitOpts(ipolicy, ispecs_mem_size, ispecs_cpu_count,
ispecs_disk_count, ispecs_disk_size,
- ispecs_nic_count, group_ipolicy, allowed_values):
+ ispecs_nic_count, group_ipolicy, fill_all):
try:
if ispecs_mem_size:
ispecs_mem_size = _MaybeParseUnit(ispecs_mem_size)
forced_type = TISPECS_CLUSTER_TYPES
for specs in ispecs_transposed.values():
assert type(specs) is dict
- utils.ForceDictType(specs, forced_type, allowed_values=allowed_values)
+ utils.ForceDictType(specs, forced_type)
# then transpose
ispecs = {
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:
- ipolicy[constants.ISPECS_MINMAX][key] = ispecs[key]
- ipolicy[constants.ISPECS_STD] = ispecs[constants.ISPECS_STD]
+ 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 and ret[k] != constants.VALUE_DEFAULT:
+ if k in ret:
try:
ret[k] = utils.ParseUnit(ret[k])
except (TypeError, ValueError, errors.UnitParseError), err:
return ret
-def _ParseISpec(spec, keyname, allowed_values):
+def _ParseISpec(spec, keyname, required):
ret = _ParseSpecUnit(spec, keyname)
- utils.ForceDictType(ret, constants.ISPECS_PARAMETER_TYPES,
- allowed_values=allowed_values)
+ 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):
- if minmax_ispecs is not None:
- minmax_out = {}
- for (key, spec) in minmax_ispecs.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)
- minmax_out[key] = _ParseISpec(spec, key, 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",
- allowed_values)
+ ipolicy_out[constants.ISPECS_STD] = _ParseISpec(std_ispecs, "std", False)
def CreateIPolicyFromOpts(ispecs_mem_size=None,
@param fill_all: whether for cluster policies we should ensure that
all values are filled
-
"""
- if ((ispecs_mem_size or ispecs_cpu_count or ispecs_disk_count or
- ispecs_disk_size or ispecs_nic_count) and
- (minmax_ispecs is not None or std_ispecs is not None)):
+ 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 minmax_ispecs is None and std_ispecs is None:
+ 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, allowed_values)
- else:
+ 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)