-
Iustin Pop authored
This patch exposes at command line level the grow-disk operation. Reviewed-by: imsnah
c6e911bc
gnt-instance 38.91 KiB
#!/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(",")
op = opcodes.OpQueryInstances(output_fields=selected_fields, names=[])
output = SubmitOpCode(op)
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",
}
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"]
# 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"
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)
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:
# drop lock and exec so other commands can run while we have console
utils.Unlock("cmd")
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_MD_R1, constants.LD_DRBD7, 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")
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"])
if instance.has_key("vnc_bind_address"):
buf.write(" VNC bind address: %s\n" % instance["vnc_bind_address"])
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):
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
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.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=hvm_cdrom_image_path,
vnc_bind_address=opts.vnc_bind_address)
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="<node>")
os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
metavar="<os>")
# 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="<pnode>[:<snode>]"),
cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
" a suffix is used",
default=20 * 1024, type="unit", metavar="<size>"),
cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
" suffix is used",
default=4 * 1024, type="unit", metavar="<size>"),
os_opt,
cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
default=128, type="unit", metavar="<mem>"),
make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
default=1, type="int", metavar="<PROC>"),
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="<ADDRESS>"),
make_option("--mac", dest="mac",
help="MAC address ('auto' [default], or specify address)",
default='auto', type="string", metavar="<MACADDRESS>"),
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="<bridge>"),
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="<FILENAME>"),
make_option("--initrd", dest="initrd_path",
help="Path to the instances' initrd (or 'none', or 'default')",
default=None,
type="string", metavar="<FILENAME>"),
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="<BOOTORDER>"),
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="<DIR>"),
make_option("--file-driver", dest="file_driver", help="Driver to use"
" for image files", default="loop", metavar="<DRIVER>"),
make_option("--iallocator", metavar="<NAME>",
help="Select nodes for the instance automatically using the"
" <NAME> iallocator plugin", default=None, type="string"),
make_option("--hvm-acpi", dest="hvm_acpi",
help="ACPI support for HVM (true|false)",
metavar="<BOOL>", choices=["true", "false"]),
make_option("--hvm-pae", dest="hvm_pae",
help="PAE support for HVM (true|false)",
metavar="<BOOL>", 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="<CDROMIMAGE>"),
make_option("--vnc-bind-address", dest="vnc_bind_address",
help="bind address for VNC (IP address)",
default=None, type="string", metavar="<VNCADDRESS>"),
]
commands = {
'add': (AddInstance, ARGS_ONE, add_opts,
"[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
"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] <instance>",
"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] <instance>",
"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], "[<instance>...]",
"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] <instance>", "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] <instance>", "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"),
],
"<instance> <new_name>", "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="<NAME>",
help="Select new secondary for the instance"
" automatically using the"
" <NAME> iallocator plugin (enables"
" secondary node replacement)",
default=None, type="string"),
],
"[-s|-p|-n NODE] <instance>",
"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="<mem>"),
make_option("-p", "--cpu", dest="vcpus",
help="Number of virtual CPUs",
default=None, type="int", metavar="<PROC>"),
make_option("-i", "--ip", dest="ip",
help="IP address ('none' or numeric IP)",
default=None, type="string", metavar="<ADDRESS>"),
make_option("-b", "--bridge", dest="bridge",
help="Bridge to connect this instance to",
default=None, type="string", metavar="<bridge>"),
make_option("--mac", dest="mac",
help="MAC address", default=None,
type="string", metavar="<MACADDRESS>"),
make_option("--kernel", dest="kernel_path",
help="Path to the instances' kernel (or"
" 'default')", default=None,
type="string", metavar="<FILENAME>"),
make_option("--initrd", dest="initrd_path",
help="Path to the instances' initrd (or 'none', or"
" 'default')", default=None,
type="string", metavar="<FILENAME>"),
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="<BOOTORDER>"),
make_option("--hvm-acpi", dest="hvm_acpi",
help="ACPI support for HVM (true|false)",
metavar="<BOOL>", choices=["true", "false"]),
make_option("--hvm-pae", dest="hvm_pae",
help="PAE support for HVM (true|false)",
metavar="<BOOL>", 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="<CDROMIMAGE>"),
make_option("--vnc-bind-address", dest="vnc_bind_address",
help="bind address for VNC (IP address)",
default=None, type="string", metavar="<VNCADDRESS>"),
],
"<instance>", "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],
"<instance>", "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="<PARAMS>"),
m_node_opt, m_pri_node_opt, m_sec_node_opt,
m_clust_opt, m_inst_opt,
],
"<instance>", "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="<PARAMS>"),
make_option("-t", "--type", dest="reboot_type",
help="Type of reboot: soft/hard/full",
default=constants.INSTANCE_REBOOT_SOFT,
type="string", metavar="<REBOOT>"),
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,
],
"<instance>", "Reboots an instance"),
'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
"<instance>",
"Activate an instance's disks"),
'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
"<instance>",
"Deactivate an instance's disks"),
'grow-disk': (GrowDisk, ARGS_FIXED(3), [DEBUG_OPT],
"<instance> <disk> <size>", "Grow an instance's disk"),
'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
"<node_name>", "List the tags of the given instance"),
'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
"<node_name> tag...", "Add tags to the given instance"),
'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
"<node_name> 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}))