4 # Copyright (C) 2006, 2007 Google Inc.
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 from optparse import make_option
26 from cStringIO import StringIO
28 from ganeti.cli import *
29 from ganeti import opcodes
30 from ganeti import logger
31 from ganeti import constants
32 from ganeti import utils
33 from ganeti import errors
36 _SHUTDOWN_CLUSTER = "cluster"
37 _SHUTDOWN_NODES_BOTH = "nodes"
38 _SHUTDOWN_NODES_PRI = "nodes-pri"
39 _SHUTDOWN_NODES_SEC = "nodes-sec"
40 _SHUTDOWN_INSTANCES = "instances"
46 "name", "os", "pnode", "status", "oper_ram",
50 def _ExpandMultiNames(mode, names):
51 """Expand the given names using the passed mode.
54 - mode, which can be one of _SHUTDOWN_CLUSTER, _SHUTDOWN_NODES_BOTH,
55 _SHUTDOWN_NODES_PRI, _SHUTDOWN_NODES_SEC or _SHUTDOWN_INSTANCES
56 - names, which is a list of names; for cluster, it must be empty,
57 and for node and instance it must be a list of valid item
58 names (short names are valid as usual, e.g. node1 instead of
61 For _SHUTDOWN_CLUSTER, all instances will be returned. For
62 _SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as
63 primary/secondary will be shutdown. For _SHUTDOWN_NODES_BOTH, all
64 instances having those nodes as either primary or secondary will be
65 returned. For _SHUTDOWN_INSTANCES, the given instances will be
69 if mode == _SHUTDOWN_CLUSTER:
71 raise errors.OpPrereqError("Cluster filter mode takes no arguments")
72 op = opcodes.OpQueryInstances(output_fields=["name"], names=[])
73 idata = SubmitOpCode(op)
74 inames = [row[0] for row in idata]
76 elif mode in (_SHUTDOWN_NODES_BOTH,
80 raise errors.OpPrereqError("No node names passed")
81 op = opcodes.OpQueryNodes(output_fields=["name", "pinst_list",
82 "sinst_list"], names=names)
83 ndata = SubmitOpCode(op)
84 ipri = [row[1] for row in ndata]
85 pri_names = list(itertools.chain(*ipri))
86 isec = [row[2] for row in ndata]
87 sec_names = list(itertools.chain(*isec))
88 if mode == _SHUTDOWN_NODES_BOTH:
89 inames = pri_names + sec_names
90 elif mode == _SHUTDOWN_NODES_PRI:
92 elif mode == _SHUTDOWN_NODES_SEC:
95 raise errors.ProgrammerError("Unhandled shutdown type")
97 elif mode == _SHUTDOWN_INSTANCES:
99 raise errors.OpPrereqError("No instance names passed")
100 op = opcodes.OpQueryInstances(output_fields=["name"], names=names)
101 idata = SubmitOpCode(op)
102 inames = [row[0] for row in idata]
105 raise errors.OpPrereqError("Unknown mode '%s'" % mode)
110 def _ConfirmOperation(inames, text):
111 """Ask the user to confirm an operation on a list of instances.
113 This function is used to request confirmation for doing an operation
114 on a given list of instances.
116 The inames argument is what the selection algorithm computed, and
117 the text argument is the operation we should tell the user to
118 confirm (e.g. 'shutdown' or 'startup').
120 Returns: boolean depending on user's confirmation.
124 msg = ("The %s will operate on %d instances.\n"
125 "Do you want to continue?" % (text, count))
126 affected = ("\nAffected instances:\n" +
127 "\n".join([" %s" % name for name in inames]))
129 choices = [('y', True, 'Yes, execute the %s' % text),
130 ('n', False, 'No, abort the %s' % text)]
133 choices.insert(1, ('v', 'v', 'View the list of affected instances'))
138 choice = AskUser(ask, choices)
141 choice = AskUser(msg + affected, choices)
145 def _TransformPath(user_input):
146 """Transform a user path into a canonical value.
148 This function transforms the a path passed as textual information
149 into the constants that the LU code expects.
153 if user_input.lower() == "default":
154 result_path = constants.VALUE_DEFAULT
155 elif user_input.lower() == "none":
156 result_path = constants.VALUE_NONE
158 if not os.path.isabs(user_input):
159 raise errors.OpPrereqError("Path '%s' is not an absolute filename" %
161 result_path = user_input
163 result_path = constants.VALUE_DEFAULT
168 def ListInstances(opts, args):
169 """List instances and their properties.
172 if opts.output is None:
173 selected_fields = _LIST_DEF_FIELDS
174 elif opts.output.startswith("+"):
175 selected_fields = _LIST_DEF_FIELDS + opts.output[1:].split(",")
177 selected_fields = opts.output.split(",")
179 op = opcodes.OpQueryInstances(output_fields=selected_fields, names=[])
180 output = SubmitOpCode(op)
182 if not opts.no_headers:
184 "name": "Instance", "os": "OS", "pnode": "Primary_node",
185 "snodes": "Secondary_Nodes", "admin_state": "Autostart",
186 "oper_state": "Running", "admin_ram": "Configured_memory",
187 "oper_ram": "Memory", "disk_template": "Disk_template",
188 "ip": "IP Address", "mac": "MAC Address",
189 "bridge": "Bridge", "vcpus": "VCPUs",
190 "sda_size": "Disk/0", "sdb_size": "Disk/1",
191 "status": "Status", "tags": "Tags",
196 if opts.human_readable:
197 unitfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
201 numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size", "vcpus"]
203 list_type_fields = ("tags",)
204 # change raw values to nicer strings
206 for idx, field in enumerate(selected_fields):
208 if field == "snodes":
209 val = ",".join(val) or "-"
210 elif field == "admin_state":
215 elif field == "oper_state":
222 elif field == "oper_ram":
225 elif field == "sda_size" or field == "sdb_size":
228 elif field in list_type_fields:
232 data = GenerateTable(separator=opts.separator, headers=headers,
233 fields=selected_fields, unitfields=unitfields,
234 numfields=numfields, data=output)
237 logger.ToStdout(line)
242 def AddInstance(opts, args):
243 """Add an instance to the cluster.
246 opts - class with options as members
247 args - list with a single element, the instance name
249 mem - amount of memory to allocate to instance (MiB)
250 size - amount of disk space to allocate to instance (MiB)
251 os - which OS to run on instance
252 node - node to run new instance on
257 (pnode, snode) = SplitNodeOption(opts.node)
259 kernel_path = _TransformPath(opts.kernel_path)
260 initrd_path = _TransformPath(opts.initrd_path)
262 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
263 hvm_pae = opts.hvm_pae == _VALUE_TRUE
265 if ((opts.hvm_cdrom_image_path is not None) and
266 (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)):
267 hvm_cdrom_image_path = None
269 hvm_cdrom_image_path = opts.hvm_cdrom_image_path
271 op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
272 disk_size=opts.size, swap_size=opts.swap,
273 disk_template=opts.disk_template,
274 mode=constants.INSTANCE_CREATE,
275 os_type=opts.os, pnode=pnode,
276 snode=snode, vcpus=opts.vcpus,
277 ip=opts.ip, bridge=opts.bridge,
278 start=opts.start, ip_check=opts.ip_check,
279 wait_for_sync=opts.wait_for_sync,
281 kernel_path=kernel_path,
282 initrd_path=initrd_path,
283 iallocator=opts.iallocator,
284 hvm_boot_order=opts.hvm_boot_order,
285 file_storage_dir=opts.file_storage_dir,
286 file_driver=opts.file_driver,
287 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
288 hvm_cdrom_image_path=hvm_cdrom_image_path,
289 vnc_bind_address=opts.vnc_bind_address)
295 def ReinstallInstance(opts, args):
296 """Reinstall an instance.
299 opts - class with options as members
300 args - list containing a single element, the instance name
303 instance_name = args[0]
306 usertext = ("This will reinstall the instance %s and remove"
307 " all data. Continue?") % instance_name
308 if not AskUser(usertext):
311 op = opcodes.OpReinstallInstance(instance_name=instance_name,
318 def RemoveInstance(opts, args):
319 """Remove an instance.
322 opts - class with options as members
323 args - list containing a single element, the instance name
326 instance_name = args[0]
330 usertext = ("This will remove the volumes of the instance %s"
331 " (including mirrors), thus removing all the data"
332 " of the instance. Continue?") % instance_name
333 if not AskUser(usertext):
336 op = opcodes.OpRemoveInstance(instance_name=instance_name,
337 ignore_failures=opts.ignore_failures)
342 def RenameInstance(opts, args):
343 """Rename an instance.
346 opts - class with options as members
347 args - list containing two elements, the instance name and the new name
350 op = opcodes.OpRenameInstance(instance_name=args[0],
352 ignore_ip=opts.ignore_ip)
358 def ActivateDisks(opts, args):
359 """Activate an instance's disks.
361 This serves two purposes:
362 - it allows one (as long as the instance is not running) to mount
363 the disks and modify them from the node
364 - it repairs inactive secondary drbds
367 instance_name = args[0]
368 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
369 disks_info = SubmitOpCode(op)
370 for host, iname, nname in disks_info:
371 print "%s:%s:%s" % (host, iname, nname)
375 def DeactivateDisks(opts, args):
376 """Command-line interface for _ShutdownInstanceBlockDevices.
378 This function takes the instance name, looks for its primary node
379 and the tries to shutdown its block devices on that node.
382 instance_name = args[0]
383 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
388 def GrowDisk(opts, args):
389 """Command-line interface for _ShutdownInstanceBlockDevices.
391 This function takes the instance name, looks for its primary node
392 and the tries to shutdown its block devices on that node.
397 amount = utils.ParseUnit(args[2])
398 op = opcodes.OpGrowDisk(instance_name=instance, disk=disk, amount=amount)
403 def StartupInstance(opts, args):
404 """Startup an instance.
407 opts - class with options as members
408 args - list containing a single element, the instance name
411 if opts.multi_mode is None:
412 opts.multi_mode = _SHUTDOWN_INSTANCES
413 inames = _ExpandMultiNames(opts.multi_mode, args)
415 raise errors.OpPrereqError("Selection filter does not match any instances")
416 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
417 if not (opts.force_multi or not multi_on
418 or _ConfirmOperation(inames, "startup")):
421 op = opcodes.OpStartupInstance(instance_name=name,
423 extra_args=opts.extra_args)
425 logger.ToStdout("Starting up %s" % name)
430 def RebootInstance(opts, args):
431 """Reboot an instance
434 opts - class with options as members
435 args - list containing a single element, the instance name
438 if opts.multi_mode is None:
439 opts.multi_mode = _SHUTDOWN_INSTANCES
440 inames = _ExpandMultiNames(opts.multi_mode, args)
442 raise errors.OpPrereqError("Selection filter does not match any instances")
443 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
444 if not (opts.force_multi or not multi_on
445 or _ConfirmOperation(inames, "reboot")):
448 op = opcodes.OpRebootInstance(instance_name=name,
449 reboot_type=opts.reboot_type,
450 ignore_secondaries=opts.ignore_secondaries)
456 def ShutdownInstance(opts, args):
457 """Shutdown an instance.
460 opts - class with options as members
461 args - list containing a single element, the instance name
464 if opts.multi_mode is None:
465 opts.multi_mode = _SHUTDOWN_INSTANCES
466 inames = _ExpandMultiNames(opts.multi_mode, args)
468 raise errors.OpPrereqError("Selection filter does not match any instances")
469 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
470 if not (opts.force_multi or not multi_on
471 or _ConfirmOperation(inames, "shutdown")):
474 op = opcodes.OpShutdownInstance(instance_name=name)
476 logger.ToStdout("Shutting down %s" % name)
481 def ReplaceDisks(opts, args):
482 """Replace the disks of an instance
485 opts - class with options as members
486 args - list with a single element, the instance name
489 instance_name = args[0]
490 new_2ndary = opts.new_secondary
491 iallocator = opts.iallocator
492 if opts.disks is None:
493 disks = ["sda", "sdb"]
495 disks = opts.disks.split(",")
496 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
497 mode = constants.REPLACE_DISK_ALL
498 elif opts.on_primary: # only on primary:
499 mode = constants.REPLACE_DISK_PRI
500 if new_2ndary is not None or iallocator is not None:
501 raise errors.OpPrereqError("Can't change secondary node on primary disk"
503 elif opts.on_secondary is not None or iallocator is not None:
505 mode = constants.REPLACE_DISK_SEC
507 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
508 remote_node=new_2ndary, mode=mode,
509 iallocator=iallocator)
514 def FailoverInstance(opts, args):
515 """Failover an instance.
517 The failover is done by shutting it down on its present node and
518 starting it on the secondary.
521 opts - class with options as members
522 args - list with a single element, the instance name
524 force - whether to failover without asking questions.
527 instance_name = args[0]
531 usertext = ("Failover will happen to image %s."
532 " This requires a shutdown of the instance. Continue?" %
534 if not AskUser(usertext):
537 op = opcodes.OpFailoverInstance(instance_name=instance_name,
538 ignore_consistency=opts.ignore_consistency)
543 def ConnectToInstanceConsole(opts, args):
544 """Connect to the console of an instance.
547 opts - class with options as members
548 args - list with a single element, the instance name
551 instance_name = args[0]
553 op = opcodes.OpConnectConsole(instance_name=instance_name)
554 cmd = SubmitOpCode(op)
556 if opts.show_command:
557 print utils.ShellQuoteArgs(cmd)
559 # drop lock and exec so other commands can run while we have console
562 os.execvp(cmd[0], cmd)
564 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
565 (cmd, " ".join(argv)))
569 def _FormatBlockDevInfo(buf, dev, indent_level):
570 """Show block device information.
572 This is only used by ShowInstanceConfig(), but it's too big to be
573 left for an inline definition.
576 def helper(buf, dtype, status):
577 """Format one line for physical device status."""
579 buf.write("not active\n")
581 (path, major, minor, syncp, estt, degr, ldisk) = status
585 major_string = str(major)
590 minor_string = str(minor)
592 buf.write("%s (%s:%s)" % (path, major_string, minor_string))
593 if dtype in (constants.LD_MD_R1, constants.LD_DRBD7, constants.LD_DRBD8):
594 if syncp is not None:
595 sync_text = "*RECOVERING* %5.2f%%," % syncp
597 sync_text += " ETA %ds" % estt
599 sync_text += " ETA unknown"
601 sync_text = "in sync"
603 degr_text = "*DEGRADED*"
607 ldisk_text = " *MISSING DISK*"
610 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
611 elif dtype == constants.LD_LV:
613 ldisk_text = " *FAILED* (failed drive?)"
616 buf.write(ldisk_text)
619 if dev["iv_name"] is not None:
620 data = " - %s, " % dev["iv_name"]
623 data += "type: %s" % dev["dev_type"]
624 if dev["logical_id"] is not None:
625 data += ", logical_id: %s" % (dev["logical_id"],)
626 elif dev["physical_id"] is not None:
627 data += ", physical_id: %s" % (dev["physical_id"],)
628 buf.write("%*s%s\n" % (2*indent_level, "", data))
629 buf.write("%*s primary: " % (2*indent_level, ""))
630 helper(buf, dev["dev_type"], dev["pstatus"])
633 buf.write("%*s secondary: " % (2*indent_level, ""))
634 helper(buf, dev["dev_type"], dev["sstatus"])
637 for child in dev["children"]:
638 _FormatBlockDevInfo(buf, child, indent_level+1)
641 def ShowInstanceConfig(opts, args):
642 """Compute instance run-time status.
646 op = opcodes.OpQueryInstanceData(instances=args)
647 result = SubmitOpCode(op)
648 hvm_parameters = ("hvm_acpi", "hvm_pae", "hvm_cdrom_image_path",
651 pvm_parameters = ("kernel_path", "initrd_path")
654 logger.ToStdout("No instances.")
659 for instance_name in result:
660 instance = result[instance_name]
661 buf.write("Instance name: %s\n" % instance["name"])
662 buf.write("State: configured to be %s, actual state is %s\n" %
663 (instance["config_state"], instance["run_state"]))
664 buf.write(" Nodes:\n")
665 buf.write(" - primary: %s\n" % instance["pnode"])
666 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
667 buf.write(" Operating system: %s\n" % instance["os"])
668 if instance.has_key("network_port"):
669 buf.write(" Allocated network port: %s\n" % instance["network_port"])
670 if False not in map(instance.has_key, pvm_parameters):
671 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
672 kpath = "(default: %s)" % constants.XEN_KERNEL
674 kpath = instance["kernel_path"]
675 buf.write(" Kernel path: %s\n" % kpath)
676 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
677 initrd = "(default: %s)" % constants.XEN_INITRD
678 elif instance["initrd_path"] == constants.VALUE_NONE:
681 initrd = instance["initrd_path"]
682 buf.write(" initrd: %s\n" % initrd)
683 if False not in map(instance.has_key, hvm_parameters):
685 buf.write(" - boot order: %s\n" % instance["hvm_boot_order"])
686 buf.write(" - ACPI support: %s\n" % instance["hvm_acpi"])
687 buf.write(" - PAE support: %s\n" % instance["hvm_pae"])
688 buf.write(" - virtual CDROM: %s\n" % instance["hvm_cdrom_image_path"])
689 if instance.has_key("vnc_bind_address"):
690 buf.write(" VNC bind address: %s\n" % instance["vnc_bind_address"])
691 buf.write(" Hardware:\n")
692 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
693 buf.write(" - memory: %dMiB\n" % instance["memory"])
694 buf.write(" - NICs: %s\n" %
695 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
697 for mac, ip, bridge in instance["nics"]]))
698 buf.write(" Block devices:\n")
700 for device in instance["disks"]:
701 _FormatBlockDevInfo(buf, device, 1)
703 logger.ToStdout(buf.getvalue().rstrip('\n'))
707 def SetInstanceParams(opts, args):
708 """Modifies an instance.
710 All parameters take effect only at the next restart of the instance.
713 opts - class with options as members
714 args - list with a single element, the instance name
716 memory - the new memory size
717 vcpus - the new number of cpus
718 mac - the new MAC address of the instance
721 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
722 opts.kernel_path or opts.initrd_path or opts.hvm_boot_order or
723 opts.hvm_acpi or opts.hvm_pae or opts.hvm_cdrom_image_path or
724 opts.vnc_bind_address):
725 logger.ToStdout("Please give at least one of the parameters.")
728 kernel_path = _TransformPath(opts.kernel_path)
729 initrd_path = _TransformPath(opts.initrd_path)
730 if opts.hvm_boot_order == 'default':
731 hvm_boot_order = constants.VALUE_DEFAULT
733 hvm_boot_order = opts.hvm_boot_order
735 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
736 hvm_pae = opts.hvm_pae == _VALUE_TRUE
738 if ((opts.hvm_cdrom_image_path is not None) and
739 (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)):
740 hvm_cdrom_image_path = None
742 hvm_cdrom_image_path = opts.hvm_cdrom_image_path
744 op = opcodes.OpSetInstanceParams(instance_name=args[0], mem=opts.mem,
745 vcpus=opts.vcpus, ip=opts.ip,
746 bridge=opts.bridge, mac=opts.mac,
747 kernel_path=opts.kernel_path,
748 initrd_path=opts.initrd_path,
749 hvm_boot_order=hvm_boot_order,
750 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
751 hvm_cdrom_image_path=hvm_cdrom_image_path,
752 vnc_bind_address=opts.vnc_bind_address)
754 result = SubmitOpCode(op)
757 logger.ToStdout("Modified instance %s" % args[0])
758 for param, data in result:
759 logger.ToStdout(" - %-5s -> %s" % (param, data))
760 logger.ToStdout("Please don't forget that these parameters take effect"
761 " only at the next start of the instance.")
765 # options used in more than one cmd
766 node_opt = make_option("-n", "--node", dest="node", help="Target node",
769 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
772 # multi-instance selection options
773 m_force_multi = make_option("--force-multiple", dest="force_multi",
774 help="Do not ask for confirmation when more than"
775 " one instance is affected",
776 action="store_true", default=False)
778 m_pri_node_opt = make_option("--primary", dest="multi_mode",
779 help="Filter by nodes (primary only)",
780 const=_SHUTDOWN_NODES_PRI, action="store_const")
782 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
783 help="Filter by nodes (secondary only)",
784 const=_SHUTDOWN_NODES_SEC, action="store_const")
786 m_node_opt = make_option("--node", dest="multi_mode",
787 help="Filter by nodes (primary and secondary)",
788 const=_SHUTDOWN_NODES_BOTH, action="store_const")
790 m_clust_opt = make_option("--all", dest="multi_mode",
791 help="Select all instances in the cluster",
792 const=_SHUTDOWN_CLUSTER, action="store_const")
794 m_inst_opt = make_option("--instance", dest="multi_mode",
795 help="Filter by instance name [default]",
796 const=_SHUTDOWN_INSTANCES, action="store_const")
799 # this is defined separately due to readability only
802 make_option("-n", "--node", dest="node",
803 help="Target node and optional secondary node",
804 metavar="<pnode>[:<snode>]"),
805 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
807 default=20 * 1024, type="unit", metavar="<size>"),
808 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
810 default=4 * 1024, type="unit", metavar="<size>"),
812 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
813 default=128, type="unit", metavar="<mem>"),
814 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
815 default=1, type="int", metavar="<PROC>"),
816 make_option("-t", "--disk-template", dest="disk_template",
817 help="Custom disk setup (diskless, file, plain or drbd)",
818 default=None, metavar="TEMPL"),
819 make_option("-i", "--ip", dest="ip",
820 help="IP address ('none' [default], 'auto', or specify address)",
821 default='none', type="string", metavar="<ADDRESS>"),
822 make_option("--mac", dest="mac",
823 help="MAC address ('auto' [default], or specify address)",
824 default='auto', type="string", metavar="<MACADDRESS>"),
825 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
826 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
827 make_option("-b", "--bridge", dest="bridge",
828 help="Bridge to connect this instance to",
829 default=None, metavar="<bridge>"),
830 make_option("--no-start", dest="start", default=True,
831 action="store_false", help="Don't start the instance after"
833 make_option("--no-ip-check", dest="ip_check", default=True,
834 action="store_false", help="Don't check that the instance's IP"
835 " is alive (only valid with --no-start)"),
836 make_option("--kernel", dest="kernel_path",
837 help="Path to the instances' kernel (or 'default')",
839 type="string", metavar="<FILENAME>"),
840 make_option("--initrd", dest="initrd_path",
841 help="Path to the instances' initrd (or 'none', or 'default')",
843 type="string", metavar="<FILENAME>"),
844 make_option("--hvm-boot-order", dest="hvm_boot_order",
845 help="Boot device order for HVM (one or more of [acdn])",
846 default=None, type="string", metavar="<BOOTORDER>"),
847 make_option("--file-storage-dir", dest="file_storage_dir",
848 help="Relative path under default cluster-wide file storage dir"
849 " to store file-based disks", default=None,
851 make_option("--file-driver", dest="file_driver", help="Driver to use"
852 " for image files", default="loop", metavar="<DRIVER>"),
853 make_option("--iallocator", metavar="<NAME>",
854 help="Select nodes for the instance automatically using the"
855 " <NAME> iallocator plugin", default=None, type="string"),
856 make_option("--hvm-acpi", dest="hvm_acpi",
857 help="ACPI support for HVM (true|false)",
858 metavar="<BOOL>", choices=["true", "false"]),
859 make_option("--hvm-pae", dest="hvm_pae",
860 help="PAE support for HVM (true|false)",
861 metavar="<BOOL>", choices=["true", "false"]),
862 make_option("--hvm-cdrom-image-path", dest="hvm_cdrom_image_path",
863 help="CDROM image path for HVM (absolute path or None)",
864 default=None, type="string", metavar="<CDROMIMAGE>"),
865 make_option("--vnc-bind-address", dest="vnc_bind_address",
866 help="bind address for VNC (IP address)",
867 default=None, type="string", metavar="<VNCADDRESS>"),
871 'add': (AddInstance, ARGS_ONE, add_opts,
872 "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
873 "Creates and adds a new instance to the cluster"),
874 'console': (ConnectToInstanceConsole, ARGS_ONE,
876 make_option("--show-cmd", dest="show_command",
877 action="store_true", default=False,
878 help=("Show command instead of executing it"))],
879 "[--show-cmd] <instance>",
880 "Opens a console on the specified instance"),
881 'failover': (FailoverInstance, ARGS_ONE,
882 [DEBUG_OPT, FORCE_OPT,
883 make_option("--ignore-consistency", dest="ignore_consistency",
884 action="store_true", default=False,
885 help="Ignore the consistency of the disks on"
889 "Stops the instance and starts it on the backup node, using"
890 " the remote mirror (only for instances of type drbd)"),
891 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
892 "Show information on the specified instance"),
893 'list': (ListInstances, ARGS_NONE,
894 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "",
895 "Lists the instances and their status. The available fields are"
896 " (see the man page for details): status, oper_state, oper_ram,"
897 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
898 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
899 " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
901 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
902 "[-f] <instance>", "Reinstall a stopped instance"),
903 'remove': (RemoveInstance, ARGS_ONE,
904 [DEBUG_OPT, FORCE_OPT,
905 make_option("--ignore-failures", dest="ignore_failures",
906 action="store_true", default=False,
907 help=("Remove the instance from the cluster even"
908 " if there are failures during the removal"
909 " process (shutdown, disk removal, etc.)")),
911 "[-f] <instance>", "Shuts down the instance and removes it"),
912 'rename': (RenameInstance, ARGS_FIXED(2),
914 make_option("--no-ip-check", dest="ignore_ip",
915 help="Do not check that the IP of the new name"
917 default=False, action="store_true"),
919 "<instance> <new_name>", "Rename the instance"),
920 'replace-disks': (ReplaceDisks, ARGS_ONE,
922 make_option("-n", "--new-secondary", dest="new_secondary",
923 help=("New secondary node (for secondary"
924 " node change)"), metavar="NODE"),
925 make_option("-p", "--on-primary", dest="on_primary",
926 default=False, action="store_true",
927 help=("Replace the disk(s) on the primary"
928 " node (only for the drbd template)")),
929 make_option("-s", "--on-secondary", dest="on_secondary",
930 default=False, action="store_true",
931 help=("Replace the disk(s) on the secondary"
932 " node (only for the drbd template)")),
933 make_option("--disks", dest="disks", default=None,
934 help=("Comma-separated list of disks"
935 " to replace (e.g. sda) (optional,"
936 " defaults to all disks")),
937 make_option("--iallocator", metavar="<NAME>",
938 help="Select new secondary for the instance"
939 " automatically using the"
940 " <NAME> iallocator plugin (enables"
941 " secondary node replacement)",
942 default=None, type="string"),
944 "[-s|-p|-n NODE] <instance>",
945 "Replaces all disks for the instance"),
946 'modify': (SetInstanceParams, ARGS_ONE,
947 [DEBUG_OPT, FORCE_OPT,
948 cli_option("-m", "--memory", dest="mem",
950 default=None, type="unit", metavar="<mem>"),
951 make_option("-p", "--cpu", dest="vcpus",
952 help="Number of virtual CPUs",
953 default=None, type="int", metavar="<PROC>"),
954 make_option("-i", "--ip", dest="ip",
955 help="IP address ('none' or numeric IP)",
956 default=None, type="string", metavar="<ADDRESS>"),
957 make_option("-b", "--bridge", dest="bridge",
958 help="Bridge to connect this instance to",
959 default=None, type="string", metavar="<bridge>"),
960 make_option("--mac", dest="mac",
961 help="MAC address", default=None,
962 type="string", metavar="<MACADDRESS>"),
963 make_option("--kernel", dest="kernel_path",
964 help="Path to the instances' kernel (or"
965 " 'default')", default=None,
966 type="string", metavar="<FILENAME>"),
967 make_option("--initrd", dest="initrd_path",
968 help="Path to the instances' initrd (or 'none', or"
969 " 'default')", default=None,
970 type="string", metavar="<FILENAME>"),
971 make_option("--hvm-boot-order", dest="hvm_boot_order",
972 help="boot device order for HVM"
973 "(either one or more of [acdn] or 'default')",
974 default=None, type="string", metavar="<BOOTORDER>"),
975 make_option("--hvm-acpi", dest="hvm_acpi",
976 help="ACPI support for HVM (true|false)",
977 metavar="<BOOL>", choices=["true", "false"]),
978 make_option("--hvm-pae", dest="hvm_pae",
979 help="PAE support for HVM (true|false)",
980 metavar="<BOOL>", choices=["true", "false"]),
981 make_option("--hvm-cdrom-image-path",
982 dest="hvm_cdrom_image_path",
983 help="CDROM image path for HVM"
984 "(absolute path or None)",
985 default=None, type="string", metavar="<CDROMIMAGE>"),
986 make_option("--vnc-bind-address", dest="vnc_bind_address",
987 help="bind address for VNC (IP address)",
988 default=None, type="string", metavar="<VNCADDRESS>"),
990 "<instance>", "Alters the parameters of an instance"),
991 'shutdown': (ShutdownInstance, ARGS_ANY,
992 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
993 m_clust_opt, m_inst_opt, m_force_multi],
994 "<instance>", "Stops an instance"),
995 'startup': (StartupInstance, ARGS_ANY,
996 [DEBUG_OPT, FORCE_OPT, m_force_multi,
997 make_option("-e", "--extra", dest="extra_args",
998 help="Extra arguments for the instance's kernel",
999 default=None, type="string", metavar="<PARAMS>"),
1000 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1001 m_clust_opt, m_inst_opt,
1003 "<instance>", "Starts an instance"),
1005 'reboot': (RebootInstance, ARGS_ANY,
1006 [DEBUG_OPT, m_force_multi,
1007 make_option("-e", "--extra", dest="extra_args",
1008 help="Extra arguments for the instance's kernel",
1009 default=None, type="string", metavar="<PARAMS>"),
1010 make_option("-t", "--type", dest="reboot_type",
1011 help="Type of reboot: soft/hard/full",
1012 default=constants.INSTANCE_REBOOT_SOFT,
1013 type="string", metavar="<REBOOT>"),
1014 make_option("--ignore-secondaries", dest="ignore_secondaries",
1015 default=False, action="store_true",
1016 help="Ignore errors from secondaries"),
1017 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1018 m_clust_opt, m_inst_opt,
1020 "<instance>", "Reboots an instance"),
1021 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
1023 "Activate an instance's disks"),
1024 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
1026 "Deactivate an instance's disks"),
1027 'grow-disk': (GrowDisk, ARGS_FIXED(3), [DEBUG_OPT],
1028 "<instance> <disk> <size>", "Grow an instance's disk"),
1029 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
1030 "<node_name>", "List the tags of the given instance"),
1031 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1032 "<node_name> tag...", "Add tags to the given instance"),
1033 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1034 "<node_name> tag...", "Remove tags from given instance"),
1038 'activate_block_devs': 'activate-disks',
1039 'replace_disks': 'replace-disks',
1044 if __name__ == '__main__':
1045 sys.exit(GenericMain(commands, aliases=aliases,
1046 override={"tag_type": constants.TAG_INSTANCE}))