"PREALLOC_WIPE_DISKS_OPT",
"PRIMARY_IP_VERSION_OPT",
"PRIMARY_ONLY_OPT",
+ "PRINT_JOBID_OPT",
"PRIORITY_OPT",
"RAPI_CERT_OPT",
"READD_OPT",
"SRC_DIR_OPT",
"SRC_NODE_OPT",
"SUBMIT_OPT",
+ "SUBMIT_OPTS",
"STARTUP_PAUSED_OPT",
"STATIC_OPT",
"SYNC_OPT",
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
help=("Submit the job and return the job ID, but"
" don't wait for the job to finish"))
+PRINT_JOBID_OPT = cli_option("--print-jobid", dest="print_jobid",
+ default=False, action="store_true",
+ help=("Additionally print the job as first line"
+ " on stdout (for scripting)."))
+
SYNC_OPT = cli_option("--sync", dest="do_locking",
default=False, action="store_true",
help=("Grab locks while doing the queries"
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"
#: Options provided by all commands
COMMON_OPTS = [DEBUG_OPT, REASON_OPT]
+# options related to asynchronous job handling
+
+SUBMIT_OPTS = [
+ SUBMIT_OPT,
+ PRINT_JOBID_OPT,
+ ]
+
# common options for creating instances. add and import then add their own
# specific ones.
COMMON_CREATE_OPTS = [
OSPARAMS_OPT,
OS_SIZE_OPT,
SUBMIT_OPT,
+ PRINT_JOBID_OPT,
TAG_ADD_OPT,
DRY_RUN_OPT,
PRIORITY_OPT,
SetGenericOpcodeOpts([op], opts)
job_id = SendJob([op], cl=cl)
+ if hasattr(opts, "print_jobid") and opts.print_jobid:
+ ToStdout("%d" % job_id)
op_results = PollJob(job_id, cl=cl, feedback_fn=feedback_fn,
reporter=reporter)
job = [op]
SetGenericOpcodeOpts(job, opts)
job_id = SendJob(job, cl=cl)
+ if opts.print_jobid:
+ ToStdout("%d" % job_id)
raise JobSubmittedException(job_id)
else:
return SubmitOpCode(op, cl=cl, feedback_fn=feedback_fn, opts=opts)
raise errors.OpPrereqError("Invalid disk size for disk %d: %s" %
(didx, err), errors.ECODE_INVAL)
elif constants.IDISK_ADOPT in ddict:
+ if constants.IDISK_SPINDLES in ddict:
+ raise errors.OpPrereqError("spindles is not a valid option when"
+ " adopting a disk", errors.ECODE_INVAL)
if mode == constants.INSTANCE_IMPORT:
raise errors.OpPrereqError("Disk adoption not allowed for instance"
" import", errors.ECODE_INVAL)
if iscluster:
eff_ipolicy = custom_ipolicy
- 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
- ]
+ minmax_out = []
+ custom_minmax = custom_ipolicy.get(constants.ISPECS_MINMAX)
+ 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]))
)
if stdspecs:
buf.write(" %s " % IPOLICY_STD_SPECS_STR)
_PrintSpecsParameters(buf, stdspecs)
- minmax = ipolicy.get("minmax")
- if minmax:
+ minmaxes = ipolicy.get("minmax", [])
+ first = True
+ for minmax in minmaxes:
minspecs = minmax.get("min")
maxspecs = minmax.get("max")
if minspecs and maxspecs:
- buf.write(" %s " % IPOLICY_BOUNDS_SPECS_STR)
+ if first:
+ buf.write(" %s " % IPOLICY_BOUNDS_SPECS_STR)
+ first = False
+ else:
+ buf.write("//")
buf.write("min:")
_PrintSpecsParameters(buf, minspecs)
buf.write("/max:")
for key, val in specs.items(): # {min: .. ,max: .., std: ..}
assert key in ispecs
ispecs[key][name] = val
- ipolicy[constants.ISPECS_MINMAX] = {}
+ minmax_out = {}
for key in constants.ISPECS_MINMAX_KEYS:
if fill_all:
- ipolicy[constants.ISPECS_MINMAX][key] = \
+ minmax_out[key] = \
objects.FillDict(constants.ISPECS_MINMAX_DEFAULTS[key], ispecs[key])
else:
- ipolicy[constants.ISPECS_MINMAX][key] = ispecs[key]
+ 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],
def _GetISpecsInAllowedValues(minmax_ispecs, allowed_values):
ret = None
- if minmax_ispecs and allowed_values and len(minmax_ispecs) == 1:
- for (key, spec) in minmax_ispecs.items():
+ 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
if found_allowed is not None:
ipolicy_out[constants.ISPECS_MINMAX] = found_allowed
elif 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, True)
+ 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