#!/usr/bin/python # # Copyright (C) 2006, 2007 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 # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. import sys import os import itertools from optparse import make_option from cStringIO import StringIO from ganeti.cli import * from ganeti import opcodes from ganeti import logger from ganeti import constants from ganeti import utils from ganeti import errors _SHUTDOWN_CLUSTER = "cluster" _SHUTDOWN_NODES_BOTH = "nodes" _SHUTDOWN_NODES_PRI = "nodes-pri" _SHUTDOWN_NODES_SEC = "nodes-sec" _SHUTDOWN_INSTANCES = "instances" _VALUE_TRUE = "true" _LIST_DEF_FIELDS = [ "name", "os", "pnode", "status", "oper_ram", ] def _ExpandMultiNames(mode, names): """Expand the given names using the passed mode. Args: - mode, which can be one of _SHUTDOWN_CLUSTER, _SHUTDOWN_NODES_BOTH, _SHUTDOWN_NODES_PRI, _SHUTDOWN_NODES_SEC or _SHUTDOWN_INSTANCES - names, which is a list of names; for cluster, it must be empty, and for node and instance it must be a list of valid item names (short names are valid as usual, e.g. node1 instead of node1.example.com) For _SHUTDOWN_CLUSTER, all instances will be returned. For _SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as primary/secondary will be shutdown. For _SHUTDOWN_NODES_BOTH, all instances having those nodes as either primary or secondary will be returned. For _SHUTDOWN_INSTANCES, the given instances will be returned. """ if mode == _SHUTDOWN_CLUSTER: if names: raise errors.OpPrereqError("Cluster filter mode takes no arguments") op = opcodes.OpQueryInstances(output_fields=["name"], names=[]) idata = SubmitOpCode(op) inames = [row[0] for row in idata] elif mode in (_SHUTDOWN_NODES_BOTH, _SHUTDOWN_NODES_PRI, _SHUTDOWN_NODES_SEC): if not names: raise errors.OpPrereqError("No node names passed") op = opcodes.OpQueryNodes(output_fields=["name", "pinst_list", "sinst_list"], names=names) ndata = SubmitOpCode(op) ipri = [row[1] for row in ndata] pri_names = list(itertools.chain(*ipri)) isec = [row[2] for row in ndata] sec_names = list(itertools.chain(*isec)) if mode == _SHUTDOWN_NODES_BOTH: inames = pri_names + sec_names elif mode == _SHUTDOWN_NODES_PRI: inames = pri_names elif mode == _SHUTDOWN_NODES_SEC: inames = sec_names else: raise errors.ProgrammerError("Unhandled shutdown type") elif mode == _SHUTDOWN_INSTANCES: if not names: raise errors.OpPrereqError("No instance names passed") op = opcodes.OpQueryInstances(output_fields=["name"], names=names) idata = SubmitOpCode(op) inames = [row[0] for row in idata] else: raise errors.OpPrereqError("Unknown mode '%s'" % mode) return inames def _ConfirmOperation(inames, text): """Ask the user to confirm an operation on a list of instances. This function is used to request confirmation for doing an operation on a given list of instances. The inames argument is what the selection algorithm computed, and the text argument is the operation we should tell the user to confirm (e.g. 'shutdown' or 'startup'). Returns: boolean depending on user's confirmation. """ count = len(inames) msg = ("The %s will operate on %d instances.\n" "Do you want to continue?" % (text, count)) affected = ("\nAffected instances:\n" + "\n".join([" %s" % name for name in inames])) choices = [('y', True, 'Yes, execute the %s' % text), ('n', False, 'No, abort the %s' % text)] if count > 20: choices.insert(1, ('v', 'v', 'View the list of affected instances')) ask = msg else: ask = msg + affected choice = AskUser(ask, choices) if choice == 'v': choices.pop(1) choice = AskUser(msg + affected, choices) return choice def _TransformPath(user_input): """Transform a user path into a canonical value. This function transforms the a path passed as textual information into the constants that the LU code expects. """ if user_input: if user_input.lower() == "default": result_path = constants.VALUE_DEFAULT elif user_input.lower() == "none": result_path = constants.VALUE_NONE else: if not os.path.isabs(user_input): raise errors.OpPrereqError("Path '%s' is not an absolute filename" % user_input) result_path = user_input else: result_path = constants.VALUE_DEFAULT return result_path def ListInstances(opts, args): """List instances and their properties. """ if opts.output is None: selected_fields = _LIST_DEF_FIELDS elif opts.output.startswith("+"): selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",") else: selected_fields = opts.output.split(",") output = GetClient().QueryInstances([], selected_fields) if not opts.no_headers: headers = { "name": "Instance", "os": "OS", "pnode": "Primary_node", "snodes": "Secondary_Nodes", "admin_state": "Autostart", "oper_state": "Running", "admin_ram": "Configured_memory", "oper_ram": "Memory", "disk_template": "Disk_template", "ip": "IP Address", "mac": "MAC Address", "bridge": "Bridge", "vcpus": "VCPUs", "sda_size": "Disk/0", "sdb_size": "Disk/1", "status": "Status", "tags": "Tags", } else: headers = None if opts.human_readable: unitfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"] else: unitfields = None numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size", "vcpus"] list_type_fields = ("tags",) # change raw values to nicer strings for row in output: for idx, field in enumerate(selected_fields): val = row[idx] if field == "snodes": val = ",".join(val) or "-" elif field == "admin_state": if val: val = "yes" else: val = "no" elif field == "oper_state": if val is None: val = "(node down)" elif val: # True val = "running" else: val = "stopped" elif field == "oper_ram": if val is None: val = "(node down)" elif field == "sda_size" or field == "sdb_size": if val is None: val = "N/A" elif field in list_type_fields: val = ",".join(val) row[idx] = str(val) data = GenerateTable(separator=opts.separator, headers=headers, fields=selected_fields, unitfields=unitfields, numfields=numfields, data=output) for line in data: logger.ToStdout(line) return 0 def AddInstance(opts, args): """Add an instance to the cluster. Args: opts - class with options as members args - list with a single element, the instance name Opts used: mem - amount of memory to allocate to instance (MiB) size - amount of disk space to allocate to instance (MiB) os - which OS to run on instance node - node to run new instance on """ instance = args[0] (pnode, snode) = SplitNodeOption(opts.node) kernel_path = _TransformPath(opts.kernel_path) initrd_path = _TransformPath(opts.initrd_path) hvm_acpi = opts.hvm_acpi == _VALUE_TRUE hvm_pae = opts.hvm_pae == _VALUE_TRUE if ((opts.hvm_cdrom_image_path is not None) and (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)): hvm_cdrom_image_path = None else: hvm_cdrom_image_path = opts.hvm_cdrom_image_path op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem, disk_size=opts.size, swap_size=opts.swap, disk_template=opts.disk_template, mode=constants.INSTANCE_CREATE, os_type=opts.os, pnode=pnode, snode=snode, vcpus=opts.vcpus, ip=opts.ip, bridge=opts.bridge, start=opts.start, ip_check=opts.ip_check, wait_for_sync=opts.wait_for_sync, mac=opts.mac, kernel_path=kernel_path, initrd_path=initrd_path, iallocator=opts.iallocator, hvm_boot_order=opts.hvm_boot_order, file_storage_dir=opts.file_storage_dir, file_driver=opts.file_driver, hvm_acpi=hvm_acpi, hvm_pae=hvm_pae, hvm_cdrom_image_path=hvm_cdrom_image_path, vnc_bind_address=opts.vnc_bind_address, hvm_nic_type=opts.hvm_nic_type, hvm_disk_type=opts.hvm_disk_type) SubmitOpCode(op) return 0 def ReinstallInstance(opts, args): """Reinstall an instance. Args: opts - class with options as members args - list containing a single element, the instance name """ instance_name = args[0] if not opts.force: usertext = ("This will reinstall the instance %s and remove" " all data. Continue?") % instance_name if not AskUser(usertext): return 1 op = opcodes.OpReinstallInstance(instance_name=instance_name, os_type=opts.os) SubmitOpCode(op) return 0 def RemoveInstance(opts, args): """Remove an instance. Args: opts - class with options as members args - list containing a single element, the instance name """ instance_name = args[0] force = opts.force if not force: usertext = ("This will remove the volumes of the instance %s" " (including mirrors), thus removing all the data" " of the instance. Continue?") % instance_name if not AskUser(usertext): return 1 op = opcodes.OpRemoveInstance(instance_name=instance_name, ignore_failures=opts.ignore_failures) SubmitOpCode(op) return 0 def RenameInstance(opts, args): """Rename an instance. Args: opts - class with options as members args - list containing two elements, the instance name and the new name """ op = opcodes.OpRenameInstance(instance_name=args[0], new_name=args[1], ignore_ip=opts.ignore_ip) SubmitOpCode(op) return 0 def ActivateDisks(opts, args): """Activate an instance's disks. This serves two purposes: - it allows one (as long as the instance is not running) to mount the disks and modify them from the node - it repairs inactive secondary drbds """ instance_name = args[0] op = opcodes.OpActivateInstanceDisks(instance_name=instance_name) disks_info = SubmitOpCode(op) for host, iname, nname in disks_info: print "%s:%s:%s" % (host, iname, nname) return 0 def DeactivateDisks(opts, args): """Command-line interface for _ShutdownInstanceBlockDevices. This function takes the instance name, looks for its primary node and the tries to shutdown its block devices on that node. """ instance_name = args[0] op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name) SubmitOpCode(op) return 0 def GrowDisk(opts, args): """Command-line interface for _ShutdownInstanceBlockDevices. This function takes the instance name, looks for its primary node and the tries to shutdown its block devices on that node. """ instance = args[0] disk = args[1] amount = utils.ParseUnit(args[2]) op = opcodes.OpGrowDisk(instance_name=instance, disk=disk, amount=amount) SubmitOpCode(op) return 0 def StartupInstance(opts, args): """Startup an instance. Args: opts - class with options as members args - list containing a single element, the instance name """ if opts.multi_mode is None: opts.multi_mode = _SHUTDOWN_INSTANCES inames = _ExpandMultiNames(opts.multi_mode, args) if not inames: raise errors.OpPrereqError("Selection filter does not match any instances") multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1 if not (opts.force_multi or not multi_on or _ConfirmOperation(inames, "startup")): return 1 for name in inames: op = opcodes.OpStartupInstance(instance_name=name, force=opts.force, extra_args=opts.extra_args) if multi_on: logger.ToStdout("Starting up %s" % name) SubmitOpCode(op) return 0 def RebootInstance(opts, args): """Reboot an instance Args: opts - class with options as members args - list containing a single element, the instance name """ if opts.multi_mode is None: opts.multi_mode = _SHUTDOWN_INSTANCES inames = _ExpandMultiNames(opts.multi_mode, args) if not inames: raise errors.OpPrereqError("Selection filter does not match any instances") multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1 if not (opts.force_multi or not multi_on or _ConfirmOperation(inames, "reboot")): return 1 for name in inames: op = opcodes.OpRebootInstance(instance_name=name, reboot_type=opts.reboot_type, ignore_secondaries=opts.ignore_secondaries) SubmitOpCode(op) return 0 def ShutdownInstance(opts, args): """Shutdown an instance. Args: opts - class with options as members args - list containing a single element, the instance name """ if opts.multi_mode is None: opts.multi_mode = _SHUTDOWN_INSTANCES inames = _ExpandMultiNames(opts.multi_mode, args) if not inames: raise errors.OpPrereqError("Selection filter does not match any instances") multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1 if not (opts.force_multi or not multi_on or _ConfirmOperation(inames, "shutdown")): return 1 for name in inames: op = opcodes.OpShutdownInstance(instance_name=name) if multi_on: logger.ToStdout("Shutting down %s" % name) SubmitOpCode(op) return 0 def ReplaceDisks(opts, args): """Replace the disks of an instance Args: opts - class with options as members args - list with a single element, the instance name """ instance_name = args[0] new_2ndary = opts.new_secondary iallocator = opts.iallocator if opts.disks is None: disks = ["sda", "sdb"] else: disks = opts.disks.split(",") if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed mode = constants.REPLACE_DISK_ALL elif opts.on_primary: # only on primary: mode = constants.REPLACE_DISK_PRI if new_2ndary is not None or iallocator is not None: raise errors.OpPrereqError("Can't change secondary node on primary disk" " replacement") elif opts.on_secondary is not None or iallocator is not None: # only on secondary mode = constants.REPLACE_DISK_SEC op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks, remote_node=new_2ndary, mode=mode, iallocator=iallocator) SubmitOpCode(op) return 0 def FailoverInstance(opts, args): """Failover an instance. The failover is done by shutting it down on its present node and starting it on the secondary. Args: opts - class with options as members args - list with a single element, the instance name Opts used: force - whether to failover without asking questions. """ instance_name = args[0] force = opts.force if not force: usertext = ("Failover will happen to image %s." " This requires a shutdown of the instance. Continue?" % (instance_name,)) if not AskUser(usertext): return 1 op = opcodes.OpFailoverInstance(instance_name=instance_name, ignore_consistency=opts.ignore_consistency) SubmitOpCode(op) return 0 def ConnectToInstanceConsole(opts, args): """Connect to the console of an instance. Args: opts - class with options as members args - list with a single element, the instance name """ instance_name = args[0] op = opcodes.OpConnectConsole(instance_name=instance_name) cmd = SubmitOpCode(op) if opts.show_command: print utils.ShellQuoteArgs(cmd) else: try: os.execvp(cmd[0], cmd) finally: sys.stderr.write("Can't run console command %s with arguments:\n'%s'" % (cmd, " ".join(argv))) os._exit(1) def _FormatBlockDevInfo(buf, dev, indent_level): """Show block device information. This is only used by ShowInstanceConfig(), but it's too big to be left for an inline definition. """ def helper(buf, dtype, status): """Format one line for physical device status.""" if not status: buf.write("not active\n") else: (path, major, minor, syncp, estt, degr, ldisk) = status if major is None: major_string = "N/A" else: major_string = str(major) if minor is None: minor_string = "N/A" else: minor_string = str(minor) buf.write("%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 else: sync_text += " ETA unknown" else: sync_text = "in sync" if degr: degr_text = "*DEGRADED*" else: degr_text = "ok" if ldisk: ldisk_text = " *MISSING DISK*" else: ldisk_text = "" buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text)) elif dtype == constants.LD_LV: if ldisk: ldisk_text = " *FAILED* (failed drive?)" else: ldisk_text = "" buf.write(ldisk_text) buf.write("\n") if dev["iv_name"] is not None: data = " - %s, " % dev["iv_name"] else: data = " - " data += "type: %s" % dev["dev_type"] if dev["logical_id"] is not None: data += ", logical_id: %s" % (dev["logical_id"],) elif dev["physical_id"] is not None: data += ", physical_id: %s" % (dev["physical_id"],) buf.write("%*s%s\n" % (2*indent_level, "", data)) buf.write("%*s primary: " % (2*indent_level, "")) helper(buf, dev["dev_type"], dev["pstatus"]) if dev["sstatus"]: buf.write("%*s secondary: " % (2*indent_level, "")) helper(buf, dev["dev_type"], dev["sstatus"]) if dev["children"]: for child in dev["children"]: _FormatBlockDevInfo(buf, child, indent_level+1) def ShowInstanceConfig(opts, args): """Compute instance run-time status. """ retcode = 0 op = opcodes.OpQueryInstanceData(instances=args) result = SubmitOpCode(op) hvm_parameters = ("hvm_acpi", "hvm_pae", "hvm_cdrom_image_path", "hvm_boot_order", "hvm_nic_type", "hvm_disk_type") pvm_parameters = ("kernel_path", "initrd_path") if not result: logger.ToStdout("No instances.") return 1 buf = StringIO() retcode = 0 for instance_name in result: instance = result[instance_name] buf.write("Instance name: %s\n" % instance["name"]) buf.write("State: configured to be %s, actual state is %s\n" % (instance["config_state"], instance["run_state"])) buf.write(" Nodes:\n") buf.write(" - primary: %s\n" % instance["pnode"]) buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"])) buf.write(" Operating system: %s\n" % instance["os"]) if instance.has_key("network_port"): buf.write(" Allocated network port: %s\n" % instance["network_port"]) if False not in map(instance.has_key, pvm_parameters): if instance["kernel_path"] in (None, constants.VALUE_DEFAULT): kpath = "(default: %s)" % constants.XEN_KERNEL else: kpath = instance["kernel_path"] buf.write(" Kernel path: %s\n" % kpath) if instance["initrd_path"] in (None, constants.VALUE_DEFAULT): initrd = "(default: %s)" % constants.XEN_INITRD elif instance["initrd_path"] == constants.VALUE_NONE: initrd = "(none)" else: initrd = instance["initrd_path"] buf.write(" initrd: %s\n" % initrd) if False not in map(instance.has_key, hvm_parameters): buf.write(" HVM:\n") buf.write(" - boot order: %s\n" % instance["hvm_boot_order"]) buf.write(" - ACPI support: %s\n" % instance["hvm_acpi"]) buf.write(" - PAE support: %s\n" % instance["hvm_pae"]) buf.write(" - virtual CDROM: %s\n" % instance["hvm_cdrom_image_path"]) buf.write(" - virtual NIC type: %s\n" % instance["hvm_nic_type"]) buf.write(" - virtual disk type: %s\n" % instance["hvm_disk_type"]) if instance.has_key("vnc_bind_address"): buf.write(" VNC bind address: %s\n" % instance["vnc_bind_address"]) buf.write(" VNC console port: %s\n" % instance["vnc_console_port"]) buf.write(" Hardware:\n") buf.write(" - VCPUs: %d\n" % instance["vcpus"]) buf.write(" - memory: %dMiB\n" % instance["memory"]) buf.write(" - NICs: %s\n" % ", ".join(["{MAC: %s, IP: %s, bridge: %s}" % (mac, ip, bridge) for mac, ip, bridge in instance["nics"]])) buf.write(" Block devices:\n") for device in instance["disks"]: _FormatBlockDevInfo(buf, device, 1) logger.ToStdout(buf.getvalue().rstrip('\n')) return retcode def SetInstanceParams(opts, args): """Modifies an instance. All parameters take effect only at the next restart of the instance. Args: opts - class with options as members args - list with a single element, the instance name Opts used: memory - the new memory size vcpus - the new number of cpus mac - the new MAC address of the instance """ if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or opts.kernel_path or opts.initrd_path or opts.hvm_boot_order or opts.hvm_acpi or opts.hvm_pae or opts.hvm_cdrom_image_path or opts.vnc_bind_address or opts.hvm_nic_type or opts.hvm_disk_type): logger.ToStdout("Please give at least one of the parameters.") return 1 kernel_path = _TransformPath(opts.kernel_path) initrd_path = _TransformPath(opts.initrd_path) if opts.hvm_boot_order == 'default': hvm_boot_order = constants.VALUE_DEFAULT else: hvm_boot_order = opts.hvm_boot_order if opts.hvm_acpi is None: hvm_acpi = opts.hvm_acpi else: hvm_acpi = opts.hvm_acpi == _VALUE_TRUE if opts.hvm_pae is None: hvm_pae = opts.hvm_pae else: hvm_pae = opts.hvm_pae == _VALUE_TRUE if opts.hvm_nic_type == constants.VALUE_NONE: hvm_nic_type = None else: hvm_nic_type = opts.hvm_nic_type if opts.hvm_disk_type == constants.VALUE_NONE: hvm_disk_type = None else: hvm_disk_type = opts.hvm_disk_type op = opcodes.OpSetInstanceParams(instance_name=args[0], mem=opts.mem, vcpus=opts.vcpus, ip=opts.ip, bridge=opts.bridge, mac=opts.mac, kernel_path=opts.kernel_path, initrd_path=opts.initrd_path, hvm_boot_order=hvm_boot_order, hvm_acpi=hvm_acpi, hvm_pae=hvm_pae, hvm_cdrom_image_path= opts.hvm_cdrom_image_path, vnc_bind_address=opts.vnc_bind_address, hvm_nic_type=hvm_nic_type, hvm_disk_type=hvm_disk_type, force=opts.force) result = SubmitOpCode(op) if result: logger.ToStdout("Modified instance %s" % args[0]) for param, data in result: logger.ToStdout(" - %-5s -> %s" % (param, data)) logger.ToStdout("Please don't forget that these parameters take effect" " only at the next start of the instance.") return 0 # options used in more than one cmd node_opt = make_option("-n", "--node", dest="node", help="Target node", metavar="") os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run", metavar="") # multi-instance selection options m_force_multi = make_option("--force-multiple", dest="force_multi", help="Do not ask for confirmation when more than" " one instance is affected", action="store_true", default=False) m_pri_node_opt = make_option("--primary", dest="multi_mode", help="Filter by nodes (primary only)", const=_SHUTDOWN_NODES_PRI, action="store_const") m_sec_node_opt = make_option("--secondary", dest="multi_mode", help="Filter by nodes (secondary only)", const=_SHUTDOWN_NODES_SEC, action="store_const") m_node_opt = make_option("--node", dest="multi_mode", help="Filter by nodes (primary and secondary)", const=_SHUTDOWN_NODES_BOTH, action="store_const") m_clust_opt = make_option("--all", dest="multi_mode", help="Select all instances in the cluster", const=_SHUTDOWN_CLUSTER, action="store_const") m_inst_opt = make_option("--instance", dest="multi_mode", help="Filter by instance name [default]", const=_SHUTDOWN_INSTANCES, action="store_const") # this is defined separately due to readability only add_opts = [ DEBUG_OPT, make_option("-n", "--node", dest="node", help="Target node and optional secondary node", metavar="[:]"), cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless" " a suffix is used", default=20 * 1024, type="unit", metavar=""), cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a" " suffix is used", default=4 * 1024, type="unit", metavar=""), os_opt, cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)", default=128, type="unit", metavar=""), make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs", default=1, type="int", metavar=""), make_option("-t", "--disk-template", dest="disk_template", help="Custom disk setup (diskless, file, plain or drbd)", default=None, metavar="TEMPL"), make_option("-i", "--ip", dest="ip", help="IP address ('none' [default], 'auto', or specify address)", default='none', type="string", metavar="
"), make_option("--mac", dest="mac", help="MAC address ('auto' [default], or specify address)", default='auto', type="string", metavar=""), make_option("--no-wait-for-sync", dest="wait_for_sync", default=True, action="store_false", help="Don't wait for sync (DANGEROUS!)"), make_option("-b", "--bridge", dest="bridge", help="Bridge to connect this instance to", default=None, metavar=""), make_option("--no-start", dest="start", default=True, action="store_false", help="Don't start the instance after" " creation"), make_option("--no-ip-check", dest="ip_check", default=True, action="store_false", help="Don't check that the instance's IP" " is alive (only valid with --no-start)"), make_option("--kernel", dest="kernel_path", help="Path to the instances' kernel (or 'default')", default=None, type="string", metavar=""), make_option("--initrd", dest="initrd_path", help="Path to the instances' initrd (or 'none', or 'default')", default=None, type="string", metavar=""), make_option("--hvm-boot-order", dest="hvm_boot_order", help="Boot device order for HVM (one or more of [acdn])", default=None, type="string", metavar=""), make_option("--file-storage-dir", dest="file_storage_dir", help="Relative path under default cluster-wide file storage dir" " to store file-based disks", default=None, metavar=""), make_option("--file-driver", dest="file_driver", help="Driver to use" " for image files", default="loop", metavar=""), make_option("--iallocator", metavar="", help="Select nodes for the instance automatically using the" " iallocator plugin", default=None, type="string"), make_option("--hvm-acpi", dest="hvm_acpi", help="ACPI support for HVM (true|false)", metavar="", choices=["true", "false"]), make_option("--hvm-nic-type", dest="hvm_nic_type", help="Type of virtual NIC for HVM " "(rtl8139,ne2k_pci,ne2k_isa,paravirtual)", metavar="NICTYPE", choices=[constants.HT_HVM_NIC_RTL8139, constants.HT_HVM_NIC_NE2K_PCI, constants.HT_HVM_NIC_NE2K_ISA, constants.HT_HVM_DEV_PARAVIRTUAL], default=constants.HT_HVM_NIC_RTL8139), make_option("--hvm-disk-type", dest="hvm_disk_type", help="Type of virtual disks for HVM (ioemu,paravirtual)", metavar="DISKTYPE", choices=[constants.HT_HVM_DEV_IOEMU, constants.HT_HVM_DEV_PARAVIRTUAL], default=constants.HT_HVM_DEV_IOEMU,), make_option("--hvm-pae", dest="hvm_pae", help="PAE support for HVM (true|false)", metavar="", choices=["true", "false"]), make_option("--hvm-cdrom-image-path", dest="hvm_cdrom_image_path", help="CDROM image path for HVM (absolute path or None)", default=None, type="string", metavar=""), make_option("--vnc-bind-address", dest="vnc_bind_address", help="bind address for VNC (IP address)", default=None, type="string", metavar=""), ] commands = { 'add': (AddInstance, ARGS_ONE, add_opts, "[...] -t disk-type -n node[:secondary-node] -o os-type ", "Creates and adds a new instance to the cluster"), 'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT, make_option("--show-cmd", dest="show_command", action="store_true", default=False, help=("Show command instead of executing it"))], "[--show-cmd] ", "Opens a console on the specified instance"), 'failover': (FailoverInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, make_option("--ignore-consistency", dest="ignore_consistency", action="store_true", default=False, help="Ignore the consistency of the disks on" " the secondary"), ], "[-f] ", "Stops the instance and starts it on the backup node, using" " the remote mirror (only for instances of type drbd)"), 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[...]", "Show information on the specified instance"), 'list': (ListInstances, ARGS_NONE, [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_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, bridge, sda_size, sdb_size, vcpus. The default field" " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS), ), 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt], "[-f] ", "Reinstall a stopped instance"), 'remove': (RemoveInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, make_option("--ignore-failures", dest="ignore_failures", action="store_true", default=False, help=("Remove the instance from the cluster even" " if there are failures during the removal" " process (shutdown, disk removal, etc.)")), ], "[-f] ", "Shuts down the instance and removes it"), 'rename': (RenameInstance, ARGS_FIXED(2), [DEBUG_OPT, make_option("--no-ip-check", dest="ignore_ip", help="Do not check that the IP of the new name" " is alive", default=False, action="store_true"), ], " ", "Rename the instance"), 'replace-disks': (ReplaceDisks, ARGS_ONE, [DEBUG_OPT, make_option("-n", "--new-secondary", dest="new_secondary", help=("New secondary node (for secondary" " node change)"), metavar="NODE"), make_option("-p", "--on-primary", dest="on_primary", default=False, action="store_true", help=("Replace the disk(s) on the primary" " node (only for the drbd template)")), make_option("-s", "--on-secondary", dest="on_secondary", default=False, action="store_true", help=("Replace the disk(s) on the secondary" " node (only for the drbd template)")), make_option("--disks", dest="disks", default=None, help=("Comma-separated list of disks" " to replace (e.g. sda) (optional," " defaults to all disks")), make_option("--iallocator", metavar="", help="Select new secondary for the instance" " automatically using the" " iallocator plugin (enables" " secondary node replacement)", default=None, type="string"), ], "[-s|-p|-n NODE] ", "Replaces all disks for the instance"), 'modify': (SetInstanceParams, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, cli_option("-m", "--memory", dest="mem", help="Memory size", default=None, type="unit", metavar=""), make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs", default=None, type="int", metavar=""), make_option("-i", "--ip", dest="ip", help="IP address ('none' or numeric IP)", default=None, type="string", metavar="
"), make_option("-b", "--bridge", dest="bridge", help="Bridge to connect this instance to", default=None, type="string", metavar=""), make_option("--mac", dest="mac", help="MAC address", default=None, type="string", metavar=""), make_option("--kernel", dest="kernel_path", help="Path to the instances' kernel (or" " 'default')", default=None, type="string", metavar=""), make_option("--initrd", dest="initrd_path", help="Path to the instances' initrd (or 'none', or" " 'default')", default=None, type="string", metavar=""), make_option("--hvm-boot-order", dest="hvm_boot_order", help="boot device order for HVM" "(either one or more of [acdn] or 'default')", default=None, type="string", metavar=""), make_option("--hvm-acpi", dest="hvm_acpi", help="ACPI support for HVM (true|false)", metavar="", choices=["true", "false"]), make_option("--hvm-pae", dest="hvm_pae", help="PAE support for HVM (true|false)", metavar="", choices=["true", "false"]), make_option("--hvm-cdrom-image-path", dest="hvm_cdrom_image_path", help="CDROM image path for HVM" "(absolute path or None)", default=None, type="string", metavar=""), make_option("--hvm-nic-type", dest="hvm_nic_type", help="Type of virtual NIC for HVM " "(rtl8139,ne2k_pci,ne2k_isa,paravirtual)", metavar="NICTYPE", choices=[constants.HT_HVM_NIC_RTL8139, constants.HT_HVM_NIC_NE2K_PCI, constants.HT_HVM_NIC_NE2K_ISA, constants.HT_HVM_DEV_PARAVIRTUAL], default=None), make_option("--hvm-disk-type", dest="hvm_disk_type", help="Type of virtual disks for HVM " "(ioemu,paravirtual)", metavar="DISKTYPE", choices=[constants.HT_HVM_DEV_IOEMU, constants.HT_HVM_DEV_PARAVIRTUAL], default=None), make_option("--vnc-bind-address", dest="vnc_bind_address", help="bind address for VNC (IP address)", default=None, type="string", metavar=""), ], "", "Alters the parameters of an instance"), 'shutdown': (ShutdownInstance, ARGS_ANY, [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, m_force_multi], "", "Stops an instance"), 'startup': (StartupInstance, ARGS_ANY, [DEBUG_OPT, FORCE_OPT, m_force_multi, make_option("-e", "--extra", dest="extra_args", help="Extra arguments for the instance's kernel", default=None, type="string", metavar=""), m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, ], "", "Starts an instance"), 'reboot': (RebootInstance, ARGS_ANY, [DEBUG_OPT, m_force_multi, make_option("-e", "--extra", dest="extra_args", help="Extra arguments for the instance's kernel", default=None, type="string", metavar=""), make_option("-t", "--type", dest="reboot_type", help="Type of reboot: soft/hard/full", default=constants.INSTANCE_REBOOT_SOFT, type="string", metavar=""), make_option("--ignore-secondaries", dest="ignore_secondaries", default=False, action="store_true", help="Ignore errors from secondaries"), m_node_opt, m_pri_node_opt, m_sec_node_opt, m_clust_opt, m_inst_opt, ], "", "Reboots an instance"), 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT], "", "Activate an instance's disks"), 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT], "", "Deactivate an instance's disks"), 'grow-disk': (GrowDisk, ARGS_FIXED(3), [DEBUG_OPT], " ", "Grow an instance's disk"), 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT], "", "List the tags of the given instance"), 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT], " tag...", "Add tags to the given instance"), 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT], " tag...", "Remove tags from given instance"), } aliases = { 'activate_block_devs': 'activate-disks', 'replace_disks': 'replace-disks', 'start': 'startup', 'stop': 'shutdown', } if __name__ == '__main__': sys.exit(GenericMain(commands, aliases=aliases, override={"tag_type": constants.TAG_INSTANCE}))