X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/3ed2333041a4ea42c7f3187b89c59482b3f2aad5..745dae57563d2f102ec8cd30349d663336309692:/lib/client/gnt_instance.py diff --git a/lib/client/gnt_instance.py b/lib/client/gnt_instance.py index 12f7189..0f70021 100644 --- a/lib/client/gnt_instance.py +++ b/lib/client/gnt_instance.py @@ -39,6 +39,7 @@ from ganeti import errors from ganeti import netutils from ganeti import ssh from ganeti import objects +from ganeti import ht _EXPAND_CLUSTER = "cluster" @@ -64,6 +65,7 @@ _LIST_DEF_FIELDS = [ ] +_MISSING = object() _ENV_OVERRIDE = frozenset(["list"]) @@ -601,14 +603,29 @@ def RecreateDisks(opts, args): """ instance_name = args[0] + + disks = [] + if opts.disks: - try: - opts.disks = [int(v) for v in opts.disks.split(",")] - except (ValueError, TypeError), err: - ToStderr("Invalid disks value: %s" % str(err)) - return 1 - else: - opts.disks = [] + for didx, ddict in opts.disks: + didx = int(didx) + + if not ht.TDict(ddict): + msg = "Invalid disk/%d value: expected dict, got %s" % (didx, ddict) + raise errors.OpPrereqError(msg) + + if constants.IDISK_SIZE in ddict: + try: + ddict[constants.IDISK_SIZE] = \ + utils.ParseUnit(ddict[constants.IDISK_SIZE]) + except ValueError, err: + raise errors.OpPrereqError("Invalid disk size for disk %d: %s" % + (didx, err)) + + disks.append((didx, ddict)) + + # TODO: Verify modifyable parameters (already done in + # LUInstanceRecreateDisks, but it'd be nice to have in the client) if opts.node: pnode, snode = SplitNodeOption(opts.node) @@ -619,9 +636,9 @@ def RecreateDisks(opts, args): nodes = [] op = opcodes.OpInstanceRecreateDisks(instance_name=instance_name, - disks=opts.disks, - nodes=nodes) + disks=disks, nodes=nodes) SubmitOrSend(op, opts) + return 0 @@ -750,7 +767,8 @@ def ReplaceDisks(opts, args): op = opcodes.OpInstanceReplaceDisks(instance_name=args[0], disks=disks, remote_node=new_2ndary, mode=mode, iallocator=iallocator, - early_release=opts.early_release) + early_release=opts.early_release, + ignore_ipolicy=opts.ignore_ipolicy) SubmitOrSend(op, opts) return 0 @@ -848,6 +866,7 @@ def MigrateInstance(opts, args): cleanup=opts.cleanup, iallocator=iallocator, target_node=target_node, allow_failover=opts.allow_failover, + allow_runtime_changes=opts.allow_runtime_chgs, ignore_ipolicy=opts.ignore_ipolicy) SubmitOpCode(op, cl=cl, opts=opts) return 0 @@ -877,7 +896,8 @@ def MoveInstance(opts, args): op = opcodes.OpInstanceMove(instance_name=instance_name, target_node=opts.node, shutdown_timeout=opts.shutdown_timeout, - ignore_consistency=opts.ignore_consistency) + ignore_consistency=opts.ignore_consistency, + ignore_ipolicy=opts.ignore_ipolicy) SubmitOrSend(op, opts, cl=cl) return 0 @@ -1183,7 +1203,15 @@ def ShowInstanceConfig(opts, args): ## instance["auto_balance"]) buf.write(" Nodes:\n") buf.write(" - primary: %s\n" % instance["pnode"]) - buf.write(" - secondaries: %s\n" % utils.CommaJoin(instance["snodes"])) + buf.write(" group: %s (UUID %s)\n" % + (instance["pnode_group_name"], instance["pnode_group_uuid"])) + buf.write(" - secondaries: %s\n" % + utils.CommaJoin("%s (group %s, group UUID %s)" % + (name, group_name, group_uuid) + for (name, group_name, group_uuid) in + zip(instance["snodes"], + instance["snodes_group_names"], + instance["snodes_group_uuids"]))) buf.write(" Operating system: %s\n" % instance["os"]) FormatParameterDict(buf, instance["os_instance"], instance["os_actual"], level=2) @@ -1248,6 +1276,78 @@ def ShowInstanceConfig(opts, args): return retcode +def _ConvertNicDiskModifications(mods): + """Converts NIC/disk modifications from CLI to opcode. + + When L{opcodes.OpInstanceSetParams} was changed to support adding/removing + disks at arbitrary indices, its parameter format changed. This function + converts legacy requests (e.g. "--net add" or "--disk add:size=4G") to the + newer format and adds support for new-style requests (e.g. "--new 4:add"). + + @type mods: list of tuples + @param mods: Modifications as given by command line parser + @rtype: list of tuples + @return: Modifications as understood by L{opcodes.OpInstanceSetParams} + + """ + result = [] + + for (idx, params) in mods: + if idx == constants.DDM_ADD: + # Add item as last item (legacy interface) + action = constants.DDM_ADD + idxno = -1 + elif idx == constants.DDM_REMOVE: + # Remove last item (legacy interface) + action = constants.DDM_REMOVE + idxno = -1 + else: + # Modifications and adding/removing at arbitrary indices + try: + idxno = int(idx) + except (TypeError, ValueError): + raise errors.OpPrereqError("Non-numeric index '%s'" % idx, + errors.ECODE_INVAL) + + add = params.pop(constants.DDM_ADD, _MISSING) + remove = params.pop(constants.DDM_REMOVE, _MISSING) + + if not (add is _MISSING or remove is _MISSING): + raise errors.OpPrereqError("Cannot add and remove at the same time", + errors.ECODE_INVAL) + elif add is not _MISSING: + action = constants.DDM_ADD + elif remove is not _MISSING: + action = constants.DDM_REMOVE + else: + action = constants.DDM_MODIFY + + assert not (constants.DDMS_VALUES_WITH_MODIFY & set(params.keys())) + + if action == constants.DDM_REMOVE and params: + raise errors.OpPrereqError("Not accepting parameters on removal", + errors.ECODE_INVAL) + + result.append((action, idxno, params)) + + return result + + +def _ParseDiskSizes(mods): + """Parses disk sizes in parameters. + + """ + for (action, _, params) in mods: + if params and constants.IDISK_SIZE in params: + params[constants.IDISK_SIZE] = \ + utils.ParseUnit(params[constants.IDISK_SIZE]) + elif action == constants.DDM_ADD: + raise errors.OpPrereqError("Missing required parameter 'size'", + errors.ECODE_INVAL) + + return mods + + def SetInstanceParams(opts, args): """Modifies an instance. @@ -1262,7 +1362,7 @@ def SetInstanceParams(opts, args): """ if not (opts.nics or opts.disks or opts.disk_template or opts.hvparams or opts.beparams or opts.os or opts.osparams or - opts.offline_inst or opts.online_inst): + opts.offline_inst or opts.online_inst or opts.runtime_mem): ToStderr("Please give at least one of the parameters.") return 1 @@ -1282,24 +1382,8 @@ def SetInstanceParams(opts, args): utils.ForceDictType(opts.hvparams, constants.HVS_PARAMETER_TYPES, allowed_values=[constants.VALUE_DEFAULT]) - for idx, (nic_op, nic_dict) in enumerate(opts.nics): - try: - nic_op = int(nic_op) - opts.nics[idx] = (nic_op, nic_dict) - except (TypeError, ValueError): - pass - - for idx, (disk_op, disk_dict) in enumerate(opts.disks): - try: - disk_op = int(disk_op) - opts.disks[idx] = (disk_op, disk_dict) - except (TypeError, ValueError): - pass - if disk_op == constants.DDM_ADD: - if "size" not in disk_dict: - raise errors.OpPrereqError("Missing required parameter 'size'", - errors.ECODE_INVAL) - disk_dict["size"] = utils.ParseUnit(disk_dict["size"]) + nics = _ConvertNicDiskModifications(opts.nics) + disks = _ParseDiskSizes(_ConvertNicDiskModifications(opts.disks)) if (opts.disk_template and opts.disk_template in constants.DTS_INT_MIRROR and @@ -1308,20 +1392,28 @@ def SetInstanceParams(opts, args): " specifying a secondary node") return 1 + if opts.offline_inst: + offline = True + elif opts.online_inst: + offline = False + else: + offline = None + op = opcodes.OpInstanceSetParams(instance_name=args[0], - nics=opts.nics, - disks=opts.disks, + nics=nics, + disks=disks, disk_template=opts.disk_template, remote_node=opts.node, hvparams=opts.hvparams, beparams=opts.beparams, + runtime_mem=opts.runtime_mem, os_name=opts.os, osparams=opts.osparams, force_variant=opts.force_variant, force=opts.force, wait_for_sync=opts.wait_for_sync, - offline_inst=opts.offline_inst, - online_inst=opts.online_inst) + offline=offline, + ignore_ipolicy=opts.ignore_ipolicy) # even if here we process the result, we allow submit only result = SubmitOrSend(op, opts) @@ -1420,6 +1512,7 @@ add_opts = [ OS_OPT, FORCE_VARIANT_OPT, NO_INSTALL_OPT, + IGNORE_IPOLICY_OPT, ] commands = { @@ -1448,13 +1541,13 @@ commands = { MigrateInstance, ARGS_ONE_INSTANCE, [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, CLEANUP_OPT, DRY_RUN_OPT, PRIORITY_OPT, DST_NODE_OPT, IALLOCATOR_OPT, ALLOW_FAILOVER_OPT, - IGNORE_IPOLICY_OPT], + IGNORE_IPOLICY_OPT, NORUNTIME_CHGS_OPT], "[-f] ", "Migrate instance to its secondary node" " (only for mirrored instances)"), "move": ( MoveInstance, ARGS_ONE_INSTANCE, [FORCE_OPT, SUBMIT_OPT, SINGLE_NODE_OPT, SHUTDOWN_TIMEOUT_OPT, - DRY_RUN_OPT, PRIORITY_OPT, IGNORE_CONSIST_OPT], + DRY_RUN_OPT, PRIORITY_OPT, IGNORE_CONSIST_OPT, IGNORE_IPOLICY_OPT], "[-f] ", "Move instance to an arbitrary node" " (only for instances of type file and lv)"), "info": ( @@ -1498,7 +1591,7 @@ commands = { ReplaceDisks, ARGS_ONE_INSTANCE, [AUTO_REPLACE_OPT, DISKIDX_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT, NEW_SECONDARY_OPT, ON_PRIMARY_OPT, ON_SECONDARY_OPT, SUBMIT_OPT, - DRY_RUN_OPT, PRIORITY_OPT], + DRY_RUN_OPT, PRIORITY_OPT, IGNORE_IPOLICY_OPT], "[-s|-p|-n NODE|-I NAME] ", "Replaces all disks for the instance"), "modify": ( @@ -1506,7 +1599,7 @@ commands = { [BACKEND_OPT, DISK_OPT, FORCE_OPT, HVOPTS_OPT, NET_OPT, SUBMIT_OPT, DISK_TEMPLATE_OPT, SINGLE_NODE_OPT, OS_OPT, FORCE_VARIANT_OPT, OSPARAMS_OPT, DRY_RUN_OPT, PRIORITY_OPT, NWSYNC_OPT, OFFLINE_INST_OPT, - ONLINE_INST_OPT], + ONLINE_INST_OPT, IGNORE_IPOLICY_OPT, RUNTIME_MEM_OPT], "", "Alters the parameters of an instance"), "shutdown": ( GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()], @@ -1540,7 +1633,7 @@ commands = { "[-f] ", "Deactivate an instance's disks"), "recreate-disks": ( RecreateDisks, ARGS_ONE_INSTANCE, - [SUBMIT_OPT, DISKIDX_OPT, NODE_PLACEMENT_OPT, DRY_RUN_OPT, PRIORITY_OPT], + [SUBMIT_OPT, DISK_OPT, NODE_PLACEMENT_OPT, DRY_RUN_OPT, PRIORITY_OPT], "", "Recreate an instance's disks"), "grow-disk": ( GrowDisk, @@ -1553,15 +1646,15 @@ commands = { [TO_GROUP_OPT, IALLOCATOR_OPT, EARLY_RELEASE_OPT], "[-I ] [--to ]", "Change group of instance"), "list-tags": ( - ListTags, ARGS_ONE_INSTANCE, [PRIORITY_OPT], + ListTags, ARGS_ONE_INSTANCE, [], "", "List the tags of the given instance"), "add-tags": ( AddTags, [ArgInstance(min=1, max=1), ArgUnknown()], - [TAG_SRC_OPT, PRIORITY_OPT], + [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT], " tag...", "Add tags to the given instance"), "remove-tags": ( RemoveTags, [ArgInstance(min=1, max=1), ArgUnknown()], - [TAG_SRC_OPT, PRIORITY_OPT], + [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT], " tag...", "Remove tags from given instance"), } @@ -1569,6 +1662,7 @@ commands = { aliases = { "start": "startup", "stop": "shutdown", + "show": "info", }