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)
560 os.execvp(cmd[0], cmd)
562 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
563 (cmd, " ".join(argv)))
567 def _FormatBlockDevInfo(buf, dev, indent_level):
568 """Show block device information.
570 This is only used by ShowInstanceConfig(), but it's too big to be
571 left for an inline definition.
574 def helper(buf, dtype, status):
575 """Format one line for physical device status."""
577 buf.write("not active\n")
579 (path, major, minor, syncp, estt, degr, ldisk) = status
583 major_string = str(major)
588 minor_string = str(minor)
590 buf.write("%s (%s:%s)" % (path, major_string, minor_string))
591 if dtype in (constants.LD_DRBD8, ):
592 if syncp is not None:
593 sync_text = "*RECOVERING* %5.2f%%," % syncp
595 sync_text += " ETA %ds" % estt
597 sync_text += " ETA unknown"
599 sync_text = "in sync"
601 degr_text = "*DEGRADED*"
605 ldisk_text = " *MISSING DISK*"
608 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
609 elif dtype == constants.LD_LV:
611 ldisk_text = " *FAILED* (failed drive?)"
614 buf.write(ldisk_text)
617 if dev["iv_name"] is not None:
618 data = " - %s, " % dev["iv_name"]
621 data += "type: %s" % dev["dev_type"]
622 if dev["logical_id"] is not None:
623 data += ", logical_id: %s" % (dev["logical_id"],)
624 elif dev["physical_id"] is not None:
625 data += ", physical_id: %s" % (dev["physical_id"],)
626 buf.write("%*s%s\n" % (2*indent_level, "", data))
627 buf.write("%*s primary: " % (2*indent_level, ""))
628 helper(buf, dev["dev_type"], dev["pstatus"])
631 buf.write("%*s secondary: " % (2*indent_level, ""))
632 helper(buf, dev["dev_type"], dev["sstatus"])
635 for child in dev["children"]:
636 _FormatBlockDevInfo(buf, child, indent_level+1)
639 def ShowInstanceConfig(opts, args):
640 """Compute instance run-time status.
644 op = opcodes.OpQueryInstanceData(instances=args)
645 result = SubmitOpCode(op)
646 hvm_parameters = ("hvm_acpi", "hvm_pae", "hvm_cdrom_image_path",
649 pvm_parameters = ("kernel_path", "initrd_path")
652 logger.ToStdout("No instances.")
657 for instance_name in result:
658 instance = result[instance_name]
659 buf.write("Instance name: %s\n" % instance["name"])
660 buf.write("State: configured to be %s, actual state is %s\n" %
661 (instance["config_state"], instance["run_state"]))
662 buf.write(" Nodes:\n")
663 buf.write(" - primary: %s\n" % instance["pnode"])
664 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
665 buf.write(" Operating system: %s\n" % instance["os"])
666 if instance.has_key("network_port"):
667 buf.write(" Allocated network port: %s\n" % instance["network_port"])
668 if False not in map(instance.has_key, pvm_parameters):
669 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
670 kpath = "(default: %s)" % constants.XEN_KERNEL
672 kpath = instance["kernel_path"]
673 buf.write(" Kernel path: %s\n" % kpath)
674 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
675 initrd = "(default: %s)" % constants.XEN_INITRD
676 elif instance["initrd_path"] == constants.VALUE_NONE:
679 initrd = instance["initrd_path"]
680 buf.write(" initrd: %s\n" % initrd)
681 if False not in map(instance.has_key, hvm_parameters):
683 buf.write(" - boot order: %s\n" % instance["hvm_boot_order"])
684 buf.write(" - ACPI support: %s\n" % instance["hvm_acpi"])
685 buf.write(" - PAE support: %s\n" % instance["hvm_pae"])
686 buf.write(" - virtual CDROM: %s\n" % instance["hvm_cdrom_image_path"])
687 if instance.has_key("vnc_bind_address"):
688 buf.write(" VNC bind address: %s\n" % instance["vnc_bind_address"])
689 buf.write(" Hardware:\n")
690 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
691 buf.write(" - memory: %dMiB\n" % instance["memory"])
692 buf.write(" - NICs: %s\n" %
693 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
695 for mac, ip, bridge in instance["nics"]]))
696 buf.write(" Block devices:\n")
698 for device in instance["disks"]:
699 _FormatBlockDevInfo(buf, device, 1)
701 logger.ToStdout(buf.getvalue().rstrip('\n'))
705 def SetInstanceParams(opts, args):
706 """Modifies an instance.
708 All parameters take effect only at the next restart of the instance.
711 opts - class with options as members
712 args - list with a single element, the instance name
714 memory - the new memory size
715 vcpus - the new number of cpus
716 mac - the new MAC address of the instance
719 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
720 opts.kernel_path or opts.initrd_path or opts.hvm_boot_order or
721 opts.hvm_acpi or opts.hvm_pae or opts.hvm_cdrom_image_path or
722 opts.vnc_bind_address):
723 logger.ToStdout("Please give at least one of the parameters.")
726 kernel_path = _TransformPath(opts.kernel_path)
727 initrd_path = _TransformPath(opts.initrd_path)
728 if opts.hvm_boot_order == 'default':
729 hvm_boot_order = constants.VALUE_DEFAULT
731 hvm_boot_order = opts.hvm_boot_order
733 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
734 hvm_pae = opts.hvm_pae == _VALUE_TRUE
736 if ((opts.hvm_cdrom_image_path is not None) and
737 (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)):
738 hvm_cdrom_image_path = None
740 hvm_cdrom_image_path = opts.hvm_cdrom_image_path
742 op = opcodes.OpSetInstanceParams(instance_name=args[0], mem=opts.mem,
743 vcpus=opts.vcpus, ip=opts.ip,
744 bridge=opts.bridge, mac=opts.mac,
745 kernel_path=opts.kernel_path,
746 initrd_path=opts.initrd_path,
747 hvm_boot_order=hvm_boot_order,
748 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
749 hvm_cdrom_image_path=hvm_cdrom_image_path,
750 vnc_bind_address=opts.vnc_bind_address)
752 result = SubmitOpCode(op)
755 logger.ToStdout("Modified instance %s" % args[0])
756 for param, data in result:
757 logger.ToStdout(" - %-5s -> %s" % (param, data))
758 logger.ToStdout("Please don't forget that these parameters take effect"
759 " only at the next start of the instance.")
763 # options used in more than one cmd
764 node_opt = make_option("-n", "--node", dest="node", help="Target node",
767 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
770 # multi-instance selection options
771 m_force_multi = make_option("--force-multiple", dest="force_multi",
772 help="Do not ask for confirmation when more than"
773 " one instance is affected",
774 action="store_true", default=False)
776 m_pri_node_opt = make_option("--primary", dest="multi_mode",
777 help="Filter by nodes (primary only)",
778 const=_SHUTDOWN_NODES_PRI, action="store_const")
780 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
781 help="Filter by nodes (secondary only)",
782 const=_SHUTDOWN_NODES_SEC, action="store_const")
784 m_node_opt = make_option("--node", dest="multi_mode",
785 help="Filter by nodes (primary and secondary)",
786 const=_SHUTDOWN_NODES_BOTH, action="store_const")
788 m_clust_opt = make_option("--all", dest="multi_mode",
789 help="Select all instances in the cluster",
790 const=_SHUTDOWN_CLUSTER, action="store_const")
792 m_inst_opt = make_option("--instance", dest="multi_mode",
793 help="Filter by instance name [default]",
794 const=_SHUTDOWN_INSTANCES, action="store_const")
797 # this is defined separately due to readability only
800 make_option("-n", "--node", dest="node",
801 help="Target node and optional secondary node",
802 metavar="<pnode>[:<snode>]"),
803 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
805 default=20 * 1024, type="unit", metavar="<size>"),
806 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
808 default=4 * 1024, type="unit", metavar="<size>"),
810 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
811 default=128, type="unit", metavar="<mem>"),
812 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
813 default=1, type="int", metavar="<PROC>"),
814 make_option("-t", "--disk-template", dest="disk_template",
815 help="Custom disk setup (diskless, file, plain or drbd)",
816 default=None, metavar="TEMPL"),
817 make_option("-i", "--ip", dest="ip",
818 help="IP address ('none' [default], 'auto', or specify address)",
819 default='none', type="string", metavar="<ADDRESS>"),
820 make_option("--mac", dest="mac",
821 help="MAC address ('auto' [default], or specify address)",
822 default='auto', type="string", metavar="<MACADDRESS>"),
823 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
824 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
825 make_option("-b", "--bridge", dest="bridge",
826 help="Bridge to connect this instance to",
827 default=None, metavar="<bridge>"),
828 make_option("--no-start", dest="start", default=True,
829 action="store_false", help="Don't start the instance after"
831 make_option("--no-ip-check", dest="ip_check", default=True,
832 action="store_false", help="Don't check that the instance's IP"
833 " is alive (only valid with --no-start)"),
834 make_option("--kernel", dest="kernel_path",
835 help="Path to the instances' kernel (or 'default')",
837 type="string", metavar="<FILENAME>"),
838 make_option("--initrd", dest="initrd_path",
839 help="Path to the instances' initrd (or 'none', or 'default')",
841 type="string", metavar="<FILENAME>"),
842 make_option("--hvm-boot-order", dest="hvm_boot_order",
843 help="Boot device order for HVM (one or more of [acdn])",
844 default=None, type="string", metavar="<BOOTORDER>"),
845 make_option("--file-storage-dir", dest="file_storage_dir",
846 help="Relative path under default cluster-wide file storage dir"
847 " to store file-based disks", default=None,
849 make_option("--file-driver", dest="file_driver", help="Driver to use"
850 " for image files", default="loop", metavar="<DRIVER>"),
851 make_option("--iallocator", metavar="<NAME>",
852 help="Select nodes for the instance automatically using the"
853 " <NAME> iallocator plugin", default=None, type="string"),
854 make_option("--hvm-acpi", dest="hvm_acpi",
855 help="ACPI support for HVM (true|false)",
856 metavar="<BOOL>", choices=["true", "false"]),
857 make_option("--hvm-pae", dest="hvm_pae",
858 help="PAE support for HVM (true|false)",
859 metavar="<BOOL>", choices=["true", "false"]),
860 make_option("--hvm-cdrom-image-path", dest="hvm_cdrom_image_path",
861 help="CDROM image path for HVM (absolute path or None)",
862 default=None, type="string", metavar="<CDROMIMAGE>"),
863 make_option("--vnc-bind-address", dest="vnc_bind_address",
864 help="bind address for VNC (IP address)",
865 default=None, type="string", metavar="<VNCADDRESS>"),
869 'add': (AddInstance, ARGS_ONE, add_opts,
870 "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
871 "Creates and adds a new instance to the cluster"),
872 'console': (ConnectToInstanceConsole, ARGS_ONE,
874 make_option("--show-cmd", dest="show_command",
875 action="store_true", default=False,
876 help=("Show command instead of executing it"))],
877 "[--show-cmd] <instance>",
878 "Opens a console on the specified instance"),
879 'failover': (FailoverInstance, ARGS_ONE,
880 [DEBUG_OPT, FORCE_OPT,
881 make_option("--ignore-consistency", dest="ignore_consistency",
882 action="store_true", default=False,
883 help="Ignore the consistency of the disks on"
887 "Stops the instance and starts it on the backup node, using"
888 " the remote mirror (only for instances of type drbd)"),
889 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
890 "Show information on the specified instance"),
891 'list': (ListInstances, ARGS_NONE,
892 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "",
893 "Lists the instances and their status. The available fields are"
894 " (see the man page for details): status, oper_state, oper_ram,"
895 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
896 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
897 " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
899 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
900 "[-f] <instance>", "Reinstall a stopped instance"),
901 'remove': (RemoveInstance, ARGS_ONE,
902 [DEBUG_OPT, FORCE_OPT,
903 make_option("--ignore-failures", dest="ignore_failures",
904 action="store_true", default=False,
905 help=("Remove the instance from the cluster even"
906 " if there are failures during the removal"
907 " process (shutdown, disk removal, etc.)")),
909 "[-f] <instance>", "Shuts down the instance and removes it"),
910 'rename': (RenameInstance, ARGS_FIXED(2),
912 make_option("--no-ip-check", dest="ignore_ip",
913 help="Do not check that the IP of the new name"
915 default=False, action="store_true"),
917 "<instance> <new_name>", "Rename the instance"),
918 'replace-disks': (ReplaceDisks, ARGS_ONE,
920 make_option("-n", "--new-secondary", dest="new_secondary",
921 help=("New secondary node (for secondary"
922 " node change)"), metavar="NODE"),
923 make_option("-p", "--on-primary", dest="on_primary",
924 default=False, action="store_true",
925 help=("Replace the disk(s) on the primary"
926 " node (only for the drbd template)")),
927 make_option("-s", "--on-secondary", dest="on_secondary",
928 default=False, action="store_true",
929 help=("Replace the disk(s) on the secondary"
930 " node (only for the drbd template)")),
931 make_option("--disks", dest="disks", default=None,
932 help=("Comma-separated list of disks"
933 " to replace (e.g. sda) (optional,"
934 " defaults to all disks")),
935 make_option("--iallocator", metavar="<NAME>",
936 help="Select new secondary for the instance"
937 " automatically using the"
938 " <NAME> iallocator plugin (enables"
939 " secondary node replacement)",
940 default=None, type="string"),
942 "[-s|-p|-n NODE] <instance>",
943 "Replaces all disks for the instance"),
944 'modify': (SetInstanceParams, ARGS_ONE,
945 [DEBUG_OPT, FORCE_OPT,
946 cli_option("-m", "--memory", dest="mem",
948 default=None, type="unit", metavar="<mem>"),
949 make_option("-p", "--cpu", dest="vcpus",
950 help="Number of virtual CPUs",
951 default=None, type="int", metavar="<PROC>"),
952 make_option("-i", "--ip", dest="ip",
953 help="IP address ('none' or numeric IP)",
954 default=None, type="string", metavar="<ADDRESS>"),
955 make_option("-b", "--bridge", dest="bridge",
956 help="Bridge to connect this instance to",
957 default=None, type="string", metavar="<bridge>"),
958 make_option("--mac", dest="mac",
959 help="MAC address", default=None,
960 type="string", metavar="<MACADDRESS>"),
961 make_option("--kernel", dest="kernel_path",
962 help="Path to the instances' kernel (or"
963 " 'default')", default=None,
964 type="string", metavar="<FILENAME>"),
965 make_option("--initrd", dest="initrd_path",
966 help="Path to the instances' initrd (or 'none', or"
967 " 'default')", default=None,
968 type="string", metavar="<FILENAME>"),
969 make_option("--hvm-boot-order", dest="hvm_boot_order",
970 help="boot device order for HVM"
971 "(either one or more of [acdn] or 'default')",
972 default=None, type="string", metavar="<BOOTORDER>"),
973 make_option("--hvm-acpi", dest="hvm_acpi",
974 help="ACPI support for HVM (true|false)",
975 metavar="<BOOL>", choices=["true", "false"]),
976 make_option("--hvm-pae", dest="hvm_pae",
977 help="PAE support for HVM (true|false)",
978 metavar="<BOOL>", choices=["true", "false"]),
979 make_option("--hvm-cdrom-image-path",
980 dest="hvm_cdrom_image_path",
981 help="CDROM image path for HVM"
982 "(absolute path or None)",
983 default=None, type="string", metavar="<CDROMIMAGE>"),
984 make_option("--vnc-bind-address", dest="vnc_bind_address",
985 help="bind address for VNC (IP address)",
986 default=None, type="string", metavar="<VNCADDRESS>"),
988 "<instance>", "Alters the parameters of an instance"),
989 'shutdown': (ShutdownInstance, ARGS_ANY,
990 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
991 m_clust_opt, m_inst_opt, m_force_multi],
992 "<instance>", "Stops an instance"),
993 'startup': (StartupInstance, ARGS_ANY,
994 [DEBUG_OPT, FORCE_OPT, m_force_multi,
995 make_option("-e", "--extra", dest="extra_args",
996 help="Extra arguments for the instance's kernel",
997 default=None, type="string", metavar="<PARAMS>"),
998 m_node_opt, m_pri_node_opt, m_sec_node_opt,
999 m_clust_opt, m_inst_opt,
1001 "<instance>", "Starts an instance"),
1003 'reboot': (RebootInstance, ARGS_ANY,
1004 [DEBUG_OPT, m_force_multi,
1005 make_option("-e", "--extra", dest="extra_args",
1006 help="Extra arguments for the instance's kernel",
1007 default=None, type="string", metavar="<PARAMS>"),
1008 make_option("-t", "--type", dest="reboot_type",
1009 help="Type of reboot: soft/hard/full",
1010 default=constants.INSTANCE_REBOOT_SOFT,
1011 type="string", metavar="<REBOOT>"),
1012 make_option("--ignore-secondaries", dest="ignore_secondaries",
1013 default=False, action="store_true",
1014 help="Ignore errors from secondaries"),
1015 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1016 m_clust_opt, m_inst_opt,
1018 "<instance>", "Reboots an instance"),
1019 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
1021 "Activate an instance's disks"),
1022 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
1024 "Deactivate an instance's disks"),
1025 'grow-disk': (GrowDisk, ARGS_FIXED(3), [DEBUG_OPT],
1026 "<instance> <disk> <size>", "Grow an instance's disk"),
1027 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
1028 "<node_name>", "List the tags of the given instance"),
1029 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1030 "<node_name> tag...", "Add tags to the given instance"),
1031 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1032 "<node_name> tag...", "Remove tags from given instance"),
1036 'activate_block_devs': 'activate-disks',
1037 'replace_disks': 'replace-disks',
1042 if __name__ == '__main__':
1043 sys.exit(GenericMain(commands, aliases=aliases,
1044 override={"tag_type": constants.TAG_INSTANCE}))