X-Git-Url: https://code.grnet.gr/git/ganeti-local/blobdiff_plain/ef7b75b2b0270a4bdc88698316f246efe9958aec..4404ffad6d6cead8dcb46f9aee6f38bbc9aaa7ca:/scripts/gnt-instance diff --git a/scripts/gnt-instance b/scripts/gnt-instance index fb9d58f..ec19602 100755 --- a/scripts/gnt-instance +++ b/scripts/gnt-instance @@ -1,7 +1,7 @@ #!/usr/bin/python # -# Copyright (C) 2006, 2007 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -34,8 +34,10 @@ from cStringIO import StringIO from ganeti.cli import * from ganeti import opcodes from ganeti import constants +from ganeti import compat from ganeti import utils from ganeti import errors +from ganeti import netutils _SHUTDOWN_CLUSTER = "cluster" @@ -226,8 +228,9 @@ def GenericManyOps(operation, fn): for name in inames: op = fn(name, opts) jex.QueueJob(name, op) - jex.WaitOrShow(not opts.submit_only) - return 0 + results = jex.WaitOrShow(not opts.submit_only) + rcode = compat.all(row[0] for row in results) + return int(not rcode) return realfn @@ -256,6 +259,7 @@ def ListInstances(opts, args): "snodes": "Secondary_Nodes", "admin_state": "Autostart", "oper_state": "Running", "oper_ram": "Memory", "disk_template": "Disk_template", + "oper_vcpus": "VCPUs", "ip": "IP_address", "mac": "MAC_address", "nic_mode": "NIC_Mode", "nic_link": "NIC_Link", "bridge": "Bridge", @@ -314,6 +318,9 @@ def ListInstances(opts, args): elif field == "oper_ram": if val is None: val = "(node down)" + elif field == "oper_vcpus": + if val is None: + val = "(node down)" elif field == "sda_size" or field == "sdb_size": if val is None: val = "N/A" @@ -323,6 +330,8 @@ def ListInstances(opts, args): val = ",".join(str(item) for item in val) elif val is None: val = "-" + if opts.roman_integers and isinstance(val, int): + val = compat.TryToRoman(val) row[idx] = str(val) data = GenerateTable(separator=opts.separator, headers=headers, @@ -384,6 +393,7 @@ def BatchCreate(opts, args): "hypervisor": None, "hvparams": {}, "file_storage_dir": None, + "force_variant": False, "file_driver": 'loop'} def _PopulateWithDefaults(spec): @@ -423,12 +433,16 @@ def BatchCreate(opts, args): ToStderr("Can't parse the instance definition file: %s" % str(err)) return 1 + if not isinstance(instance_data, dict): + ToStderr("The instance definition file is not in dict format.") + return 1 + jex = JobExecutor(opts=opts) # Iterate over the instances and do: # * Populate the specs with default value # * Validate the instance specs - i_names = utils.NiceSort(instance_data.keys()) + i_names = utils.NiceSort(instance_data.keys()) # pylint: disable-msg=E1103 for name in i_names: specs = instance_data[name] specs = _PopulateWithDefaults(specs) @@ -471,7 +485,7 @@ def BatchCreate(opts, args): disk_template=specs['template'], mode=constants.INSTANCE_CREATE, os_type=specs['os'], - force_variant=opts.force_variant, + force_variant=specs["force_variant"], pnode=specs['primary_node'], snode=specs['secondary_node'], nics=tmp_nics, @@ -613,10 +627,19 @@ def RenameInstance(opts, args): @return: the desired exit code """ + if not opts.name_check: + if not AskUser("As you disabled the check of the DNS entry, please verify" + " that '%s' is a FQDN. Continue?" % args[1]): + return 1 + op = opcodes.OpRenameInstance(instance_name=args[0], new_name=args[1], - ignore_ip=not opts.ip_check) - SubmitOrSend(op, opts) + ip_check=opts.ip_check, + name_check=opts.name_check) + result = SubmitOrSend(op, opts) + + ToStdout("Instance '%s' renamed to '%s'", args[0], result) + return 0 @@ -872,13 +895,22 @@ def MigrateInstance(opts, args): else: usertext = ("Instance %s will be migrated. Note that migration" % (instance_name,)) - usertext += (" is **experimental** in this version." - " This might impact the instance if anything goes wrong." - " Continue?") + usertext += (" might impact the instance if anything goes wrong" + " (e.g. due to bugs in the hypervisor). Continue?") if not AskUser(usertext): return 1 - op = opcodes.OpMigrateInstance(instance_name=instance_name, live=opts.live, + # this should be removed once --non-live is deprecated + if not opts.live and opts.migration_mode is not None: + raise errors.OpPrereqError("Only one of the --non-live and " + "--migration-mode options can be passed", + errors.ECODE_INVAL) + if not opts.live: # --non-live passed + mode = constants.HT_MIGRATION_NONLIVE + else: + mode = opts.migration_mode + + op = opcodes.OpMigrateInstance(instance_name=instance_name, mode=mode, cleanup=opts.cleanup) SubmitOpCode(op, cl=cl, opts=opts) return 0 @@ -938,16 +970,18 @@ def ConnectToInstanceConsole(opts, args): os._exit(1) # pylint: disable-msg=W0212 -def _FormatLogicalID(dev_type, logical_id): +def _FormatLogicalID(dev_type, logical_id, roman): """Formats the logical_id of a disk. """ if dev_type == constants.LD_DRBD8: node_a, node_b, port, minor_a, minor_b, key = logical_id data = [ - ("nodeA", "%s, minor=%s" % (node_a, minor_a)), - ("nodeB", "%s, minor=%s" % (node_b, minor_b)), - ("port", port), + ("nodeA", "%s, minor=%s" % (node_a, compat.TryToRoman(minor_a, + convert=roman))), + ("nodeB", "%s, minor=%s" % (node_b, compat.TryToRoman(minor_b, + convert=roman))), + ("port", compat.TryToRoman(port, convert=roman)), ("auth key", key), ] elif dev_type == constants.LD_LV: @@ -959,7 +993,7 @@ def _FormatLogicalID(dev_type, logical_id): return data -def _FormatBlockDevInfo(idx, top_level, dev, static): +def _FormatBlockDevInfo(idx, top_level, dev, static, roman): """Show block device information. This is only used by L{ShowInstanceConfig}, but it's too big to be @@ -974,6 +1008,8 @@ def _FormatBlockDevInfo(idx, top_level, dev, static): @type static: boolean @param static: wheter the device information doesn't contain runtime information but only static data + @type roman: boolean + @param roman: whether to try to use roman integers @return: a list of either strings, tuples or lists (which should be formatted at a higher indent level) @@ -995,19 +1031,19 @@ def _FormatBlockDevInfo(idx, top_level, dev, static): if major is None: major_string = "N/A" else: - major_string = str(major) + major_string = str(compat.TryToRoman(major, convert=roman)) if minor is None: minor_string = "N/A" else: - minor_string = str(minor) + minor_string = str(compat.TryToRoman(minor, convert=roman)) txt += ("%s (%s:%s)" % (path, major_string, minor_string)) if dtype in (constants.LD_DRBD8, ): if syncp is not None: sync_text = "*RECOVERING* %5.2f%%," % syncp if estt: - sync_text += " ETA %ds" % estt + sync_text += " ETA %ss" % compat.TryToRoman(estt, convert=roman) else: sync_text += " ETA unknown" else: @@ -1036,9 +1072,9 @@ def _FormatBlockDevInfo(idx, top_level, dev, static): if dev["iv_name"] is not None: txt = dev["iv_name"] else: - txt = "disk %d" % idx + txt = "disk %s" % compat.TryToRoman(idx, convert=roman) else: - txt = "child %d" % idx + txt = "child %s" % compat.TryToRoman(idx, convert=roman) if isinstance(dev["size"], int): nice_size = utils.FormatUnit(dev["size"], "h") else: @@ -1049,7 +1085,7 @@ def _FormatBlockDevInfo(idx, top_level, dev, static): data.append(("access mode", dev["mode"])) if dev["logical_id"] is not None: try: - l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"]) + l_id = _FormatLogicalID(dev["dev_type"], dev["logical_id"], roman) except ValueError: l_id = [str(dev["logical_id"])] if len(l_id) == 1: @@ -1067,7 +1103,7 @@ def _FormatBlockDevInfo(idx, top_level, dev, static): if dev["children"]: data.append("child devices:") for c_idx, child in enumerate(dev["children"]): - data.append(_FormatBlockDevInfo(c_idx, False, child, static)) + data.append(_FormatBlockDevInfo(c_idx, False, child, static, roman)) d1.append(data) return d1 @@ -1101,6 +1137,21 @@ def _FormatList(buf, data, indent_level): _FormatList(buf, elem, indent_level+1) +def _FormatParameterDict(buf, per_inst, actual): + """Formats a parameter dictionary. + + @type buf: L{StringIO} + @param buf: the buffer into which to write + @type per_inst: dict + @param per_inst: the instance's own parameters + @type actual: dict + @param actual: the current parameter set (including defaults) + + """ + for key in sorted(actual): + val = per_inst.get(key, "default (%s)" % actual[key]) + buf.write(" - %s: %s\n" % (key, val)) + def ShowInstanceConfig(opts, args): """Compute instance run-time status. @@ -1134,7 +1185,9 @@ def ShowInstanceConfig(opts, args): instance = result[instance_name] buf.write("Instance name: %s\n" % instance["name"]) buf.write("UUID: %s\n" % instance["uuid"]) - buf.write("Serial number: %s\n" % instance["serial_no"]) + buf.write("Serial number: %s\n" % + compat.TryToRoman(instance["serial_no"], + convert=opts.roman_integers)) buf.write("Creation time: %s\n" % utils.FormatTime(instance["ctime"])) buf.write("Modification time: %s\n" % utils.FormatTime(instance["mtime"])) buf.write("State: configured to be %s" % instance["config_state"]) @@ -1147,8 +1200,11 @@ def ShowInstanceConfig(opts, args): buf.write(" - primary: %s\n" % instance["pnode"]) buf.write(" - secondaries: %s\n" % utils.CommaJoin(instance["snodes"])) buf.write(" Operating system: %s\n" % instance["os"]) + _FormatParameterDict(buf, instance["os_instance"], instance["os_actual"]) if instance.has_key("network_port"): - buf.write(" Allocated network port: %s\n" % instance["network_port"]) + buf.write(" Allocated network port: %s\n" % + compat.TryToRoman(instance["network_port"], + convert=opts.roman_integers)) buf.write(" Hypervisor: %s\n" % instance["hypervisor"]) # custom VNC console information @@ -1157,11 +1213,11 @@ def ShowInstanceConfig(opts, args): if vnc_bind_address: port = instance["network_port"] display = int(port) - constants.VNC_BASE_PORT - if display > 0 and vnc_bind_address == constants.BIND_ADDRESS_GLOBAL: + if display > 0 and vnc_bind_address == constants.IP4_ADDRESS_ANY: vnc_console_port = "%s:%s (display %s)" % (instance["pnode"], port, display) - elif display > 0 and utils.IsValidIP(vnc_bind_address): + elif display > 0 and netutils.IsValidIP4(vnc_bind_address): vnc_console_port = ("%s:%s (node %s) (display %s)" % (vnc_bind_address, port, instance["pnode"], display)) @@ -1171,17 +1227,14 @@ def ShowInstanceConfig(opts, args): vnc_bind_address) buf.write(" - console connection: vnc to %s\n" % vnc_console_port) - for key in instance["hv_actual"]: - if key in instance["hv_instance"]: - val = instance["hv_instance"][key] - else: - val = "default (%s)" % instance["hv_actual"][key] - buf.write(" - %s: %s\n" % (key, val)) + _FormatParameterDict(buf, instance["hv_instance"], instance["hv_actual"]) buf.write(" Hardware:\n") - buf.write(" - VCPUs: %d\n" % - instance["be_actual"][constants.BE_VCPUS]) - buf.write(" - memory: %dMiB\n" % - instance["be_actual"][constants.BE_MEMORY]) + buf.write(" - VCPUs: %s\n" % + compat.TryToRoman(instance["be_actual"][constants.BE_VCPUS], + convert=opts.roman_integers)) + buf.write(" - memory: %sMiB\n" % + compat.TryToRoman(instance["be_actual"][constants.BE_MEMORY], + convert=opts.roman_integers)) buf.write(" - NICs:\n") for idx, (ip, mac, mode, link) in enumerate(instance["nics"]): buf.write(" - nic/%d: MAC: %s, IP: %s, mode: %s, link: %s\n" % @@ -1189,7 +1242,8 @@ def ShowInstanceConfig(opts, args): buf.write(" Disks:\n") for idx, device in enumerate(instance["disks"]): - _FormatList(buf, _FormatBlockDevInfo(idx, True, device, opts.static), 2) + _FormatList(buf, _FormatBlockDevInfo(idx, True, device, opts.static, + opts.roman_integers), 2) ToStdout(buf.getvalue().rstrip('\n')) return retcode @@ -1207,8 +1261,8 @@ def SetInstanceParams(opts, args): @return: the desired exit code """ - if not (opts.nics or opts.disks or - opts.hvparams or opts.beparams): + if not (opts.nics or opts.disks or opts.disk_template or + opts.hvparams or opts.beparams or opts.os or opts.osparams): ToStderr("Please give at least one of the parameters.") return 1 @@ -1247,11 +1301,23 @@ def SetInstanceParams(opts, args): errors.ECODE_INVAL) disk_dict['size'] = utils.ParseUnit(disk_dict['size']) + if (opts.disk_template and + opts.disk_template in constants.DTS_NET_MIRROR and + not opts.node): + ToStderr("Changing the disk template to a mirrored one requires" + " specifying a secondary node") + return 1 + op = opcodes.OpSetInstanceParams(instance_name=args[0], nics=opts.nics, disks=opts.disks, + disk_template=opts.disk_template, + remote_node=opts.node, hvparams=opts.hvparams, beparams=opts.beparams, + os_name=opts.os, + osparams=opts.osparams, + force_variant=opts.force_variant, force=opts.force) # even if here we process the result, we allow submit only @@ -1261,7 +1327,7 @@ def SetInstanceParams(opts, args): ToStdout("Modified instance %s", args[0]) for param, data in result: ToStdout(" - %-5s -> %s", param, data) - ToStdout("Please don't forget that these parameters take effect" + ToStdout("Please don't forget that most parameters take effect" " only at the next start of the instance.") return 0 @@ -1328,8 +1394,10 @@ add_opts = [ NONICS_OPT, NOSTART_OPT, NWSYNC_OPT, + OSPARAMS_OPT, OS_OPT, FORCE_VARIANT_OPT, + NO_INSTALL_OPT, OS_SIZE_OPT, SUBMIT_OPT, ] @@ -1354,7 +1422,7 @@ commands = { " using the remote mirror (only for instances of type drbd)"), 'migrate': ( MigrateInstance, ARGS_ONE_INSTANCE, - [FORCE_OPT, NONLIVE_OPT, CLEANUP_OPT], + [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, CLEANUP_OPT], "[-f] ", "Migrate instance to its secondary node" " (only for instances of type drbd)"), 'move': ( @@ -1364,17 +1432,18 @@ commands = { " (only for instances of type file and lv)"), 'info': ( ShowInstanceConfig, ARGS_MANY_INSTANCES, - [STATIC_OPT, ALL_OPT], + [STATIC_OPT, ALL_OPT, ROMAN_OPT], "[-s] {--all | ...}", "Show information on the specified instance(s)"), 'list': ( ListInstances, ARGS_MANY_INSTANCES, - [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT], + [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, SYNC_OPT, ROMAN_OPT], "[...]", "Lists the instances and their status. The available fields are" " (see the man page for details): status, oper_state, oper_ram," - " name, os, pnode, snodes, admin_state, admin_ram, disk_template," - " ip, mac, nic_mode, nic_link, sda_size, sdb_size, vcpus, serial_no," + " oper_vcpus, name, os, pnode, snodes, admin_state, admin_ram," + " disk_template, ip, mac, nic_mode, nic_link, sda_size, sdb_size," + " vcpus, serial_no," " nic.count, nic.mac/N, nic.ip/N, nic.mode/N, nic.link/N," " nic.macs, nic.ips, nic.modes, nic.links," " disk.count, disk.size/N, disk.sizes," @@ -1397,7 +1466,7 @@ commands = { 'rename': ( RenameInstance, [ArgInstance(min=1, max=1), ArgHost(min=1, max=1)], - [NOIPCHECK_OPT, SUBMIT_OPT], + [NOIPCHECK_OPT, NONAMECHECK_OPT, SUBMIT_OPT], " ", "Rename the instance"), 'replace-disks': ( ReplaceDisks, ARGS_ONE_INSTANCE, @@ -1407,7 +1476,9 @@ commands = { "Replaces all disks for the instance"), 'modify': ( SetInstanceParams, ARGS_ONE_INSTANCE, - [BACKEND_OPT, DISK_OPT, FORCE_OPT, HVOPTS_OPT, NET_OPT, SUBMIT_OPT], + [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], "", "Alters the parameters of an instance"), 'shutdown': ( GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()],