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",
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 # change raw values to nicer strings
205 for idx, field in enumerate(selected_fields):
207 if field == "snodes":
208 val = ",".join(val) or "-"
209 elif field == "admin_state":
214 elif field == "oper_state":
221 elif field == "oper_ram":
224 elif field == "sda_size" or field == "sdb_size":
229 data = GenerateTable(separator=opts.separator, headers=headers,
230 fields=selected_fields, unitfields=unitfields,
231 numfields=numfields, data=output)
234 logger.ToStdout(line)
239 def AddInstance(opts, args):
240 """Add an instance to the cluster.
243 opts - class with options as members
244 args - list with a single element, the instance name
246 mem - amount of memory to allocate to instance (MiB)
247 size - amount of disk space to allocate to instance (MiB)
248 os - which OS to run on instance
249 node - node to run new instance on
254 (pnode, snode) = SplitNodeOption(opts.node)
256 kernel_path = _TransformPath(opts.kernel_path)
257 initrd_path = _TransformPath(opts.initrd_path)
259 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
260 hvm_pae = opts.hvm_pae == _VALUE_TRUE
262 if ((opts.hvm_cdrom_image_path is not None) and
263 (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)):
264 hvm_cdrom_image_path = None
266 hvm_cdrom_image_path = opts.hvm_cdrom_image_path
268 op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
269 disk_size=opts.size, swap_size=opts.swap,
270 disk_template=opts.disk_template,
271 mode=constants.INSTANCE_CREATE,
272 os_type=opts.os, pnode=pnode,
273 snode=snode, vcpus=opts.vcpus,
274 ip=opts.ip, bridge=opts.bridge,
275 start=opts.start, ip_check=opts.ip_check,
276 wait_for_sync=opts.wait_for_sync,
278 kernel_path=kernel_path,
279 initrd_path=initrd_path,
280 iallocator=opts.iallocator,
281 hvm_boot_order=opts.hvm_boot_order,
282 file_storage_dir=opts.file_storage_dir,
283 file_driver=opts.file_driver,
284 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
285 hvm_cdrom_image_path=hvm_cdrom_image_path,
286 vnc_bind_address=opts.vnc_bind_address)
292 def ReinstallInstance(opts, args):
293 """Reinstall an instance.
296 opts - class with options as members
297 args - list containing a single element, the instance name
300 instance_name = args[0]
303 usertext = ("This will reinstall the instance %s and remove"
304 " all data. Continue?") % instance_name
305 if not AskUser(usertext):
308 op = opcodes.OpReinstallInstance(instance_name=instance_name,
315 def RemoveInstance(opts, args):
316 """Remove an instance.
319 opts - class with options as members
320 args - list containing a single element, the instance name
323 instance_name = args[0]
327 usertext = ("This will remove the volumes of the instance %s"
328 " (including mirrors), thus removing all the data"
329 " of the instance. Continue?") % instance_name
330 if not AskUser(usertext):
333 op = opcodes.OpRemoveInstance(instance_name=instance_name,
334 ignore_failures=opts.ignore_failures)
339 def RenameInstance(opts, args):
340 """Rename an instance.
343 opts - class with options as members
344 args - list containing two elements, the instance name and the new name
347 op = opcodes.OpRenameInstance(instance_name=args[0],
349 ignore_ip=opts.ignore_ip)
355 def ActivateDisks(opts, args):
356 """Activate an instance's disks.
358 This serves two purposes:
359 - it allows one (as long as the instance is not running) to mount
360 the disks and modify them from the node
361 - it repairs inactive secondary drbds
364 instance_name = args[0]
365 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
366 disks_info = SubmitOpCode(op)
367 for host, iname, nname in disks_info:
368 print "%s:%s:%s" % (host, iname, nname)
372 def DeactivateDisks(opts, args):
373 """Command-line interface for _ShutdownInstanceBlockDevices.
375 This function takes the instance name, looks for its primary node
376 and the tries to shutdown its block devices on that node.
379 instance_name = args[0]
380 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
385 def GrowDisk(opts, args):
386 """Command-line interface for _ShutdownInstanceBlockDevices.
388 This function takes the instance name, looks for its primary node
389 and the tries to shutdown its block devices on that node.
394 amount = utils.ParseUnit(args[2])
395 op = opcodes.OpGrowDisk(instance_name=instance, disk=disk, amount=amount)
400 def StartupInstance(opts, args):
401 """Startup an instance.
404 opts - class with options as members
405 args - list containing a single element, the instance name
408 if opts.multi_mode is None:
409 opts.multi_mode = _SHUTDOWN_INSTANCES
410 inames = _ExpandMultiNames(opts.multi_mode, args)
412 raise errors.OpPrereqError("Selection filter does not match any instances")
413 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
414 if not (opts.force_multi or not multi_on
415 or _ConfirmOperation(inames, "startup")):
418 op = opcodes.OpStartupInstance(instance_name=name,
420 extra_args=opts.extra_args)
422 logger.ToStdout("Starting up %s" % name)
427 def RebootInstance(opts, args):
428 """Reboot an instance
431 opts - class with options as members
432 args - list containing a single element, the instance name
435 if opts.multi_mode is None:
436 opts.multi_mode = _SHUTDOWN_INSTANCES
437 inames = _ExpandMultiNames(opts.multi_mode, args)
439 raise errors.OpPrereqError("Selection filter does not match any instances")
440 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
441 if not (opts.force_multi or not multi_on
442 or _ConfirmOperation(inames, "reboot")):
445 op = opcodes.OpRebootInstance(instance_name=name,
446 reboot_type=opts.reboot_type,
447 ignore_secondaries=opts.ignore_secondaries)
453 def ShutdownInstance(opts, args):
454 """Shutdown an instance.
457 opts - class with options as members
458 args - list containing a single element, the instance name
461 if opts.multi_mode is None:
462 opts.multi_mode = _SHUTDOWN_INSTANCES
463 inames = _ExpandMultiNames(opts.multi_mode, args)
465 raise errors.OpPrereqError("Selection filter does not match any instances")
466 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
467 if not (opts.force_multi or not multi_on
468 or _ConfirmOperation(inames, "shutdown")):
471 op = opcodes.OpShutdownInstance(instance_name=name)
473 logger.ToStdout("Shutting down %s" % name)
478 def ReplaceDisks(opts, args):
479 """Replace the disks of an instance
482 opts - class with options as members
483 args - list with a single element, the instance name
486 instance_name = args[0]
487 new_2ndary = opts.new_secondary
488 iallocator = opts.iallocator
489 if opts.disks is None:
490 disks = ["sda", "sdb"]
492 disks = opts.disks.split(",")
493 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
494 mode = constants.REPLACE_DISK_ALL
495 elif opts.on_primary: # only on primary:
496 mode = constants.REPLACE_DISK_PRI
497 if new_2ndary is not None or iallocator is not None:
498 raise errors.OpPrereqError("Can't change secondary node on primary disk"
500 elif opts.on_secondary is not None or iallocator is not None:
502 mode = constants.REPLACE_DISK_SEC
504 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
505 remote_node=new_2ndary, mode=mode,
506 iallocator=iallocator)
511 def FailoverInstance(opts, args):
512 """Failover an instance.
514 The failover is done by shutting it down on its present node and
515 starting it on the secondary.
518 opts - class with options as members
519 args - list with a single element, the instance name
521 force - whether to failover without asking questions.
524 instance_name = args[0]
528 usertext = ("Failover will happen to image %s."
529 " This requires a shutdown of the instance. Continue?" %
531 if not AskUser(usertext):
534 op = opcodes.OpFailoverInstance(instance_name=instance_name,
535 ignore_consistency=opts.ignore_consistency)
540 def ConnectToInstanceConsole(opts, args):
541 """Connect to the console of an instance.
544 opts - class with options as members
545 args - list with a single element, the instance name
548 instance_name = args[0]
550 op = opcodes.OpConnectConsole(instance_name=instance_name)
551 cmd = SubmitOpCode(op)
553 if opts.show_command:
554 print utils.ShellQuoteArgs(cmd)
556 # drop lock and exec so other commands can run while we have console
559 os.execvp(cmd[0], cmd)
561 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
562 (cmd, " ".join(argv)))
566 def _FormatBlockDevInfo(buf, dev, indent_level):
567 """Show block device information.
569 This is only used by ShowInstanceConfig(), but it's too big to be
570 left for an inline definition.
573 def helper(buf, dtype, status):
574 """Format one line for physical device status."""
576 buf.write("not active\n")
578 (path, major, minor, syncp, estt, degr, ldisk) = status
582 major_string = str(major)
587 minor_string = str(minor)
589 buf.write("%s (%s:%s)" % (path, major_string, minor_string))
590 if dtype in (constants.LD_MD_R1, constants.LD_DRBD7, constants.LD_DRBD8):
591 if syncp is not None:
592 sync_text = "*RECOVERING* %5.2f%%," % syncp
594 sync_text += " ETA %ds" % estt
596 sync_text += " ETA unknown"
598 sync_text = "in sync"
600 degr_text = "*DEGRADED*"
604 ldisk_text = " *MISSING DISK*"
607 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
608 elif dtype == constants.LD_LV:
610 ldisk_text = " *FAILED* (failed drive?)"
613 buf.write(ldisk_text)
616 if dev["iv_name"] is not None:
617 data = " - %s, " % dev["iv_name"]
620 data += "type: %s" % dev["dev_type"]
621 if dev["logical_id"] is not None:
622 data += ", logical_id: %s" % (dev["logical_id"],)
623 elif dev["physical_id"] is not None:
624 data += ", physical_id: %s" % (dev["physical_id"],)
625 buf.write("%*s%s\n" % (2*indent_level, "", data))
626 buf.write("%*s primary: " % (2*indent_level, ""))
627 helper(buf, dev["dev_type"], dev["pstatus"])
630 buf.write("%*s secondary: " % (2*indent_level, ""))
631 helper(buf, dev["dev_type"], dev["sstatus"])
634 for child in dev["children"]:
635 _FormatBlockDevInfo(buf, child, indent_level+1)
638 def ShowInstanceConfig(opts, args):
639 """Compute instance run-time status.
643 op = opcodes.OpQueryInstanceData(instances=args)
644 result = SubmitOpCode(op)
645 hvm_parameters = ("hvm_acpi", "hvm_pae", "hvm_cdrom_image_path",
648 pvm_parameters = ("kernel_path", "initrd_path")
651 logger.ToStdout("No instances.")
656 for instance_name in result:
657 instance = result[instance_name]
658 buf.write("Instance name: %s\n" % instance["name"])
659 buf.write("State: configured to be %s, actual state is %s\n" %
660 (instance["config_state"], instance["run_state"]))
661 buf.write(" Nodes:\n")
662 buf.write(" - primary: %s\n" % instance["pnode"])
663 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
664 buf.write(" Operating system: %s\n" % instance["os"])
665 if instance.has_key("network_port"):
666 buf.write(" Allocated network port: %s\n" % instance["network_port"])
667 if False not in map(instance.has_key, pvm_parameters):
668 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
669 kpath = "(default: %s)" % constants.XEN_KERNEL
671 kpath = instance["kernel_path"]
672 buf.write(" Kernel path: %s\n" % kpath)
673 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
674 initrd = "(default: %s)" % constants.XEN_INITRD
675 elif instance["initrd_path"] == constants.VALUE_NONE:
678 initrd = instance["initrd_path"]
679 buf.write(" initrd: %s\n" % initrd)
680 if False not in map(instance.has_key, hvm_parameters):
682 buf.write(" - boot order: %s\n" % instance["hvm_boot_order"])
683 buf.write(" - ACPI support: %s\n" % instance["hvm_acpi"])
684 buf.write(" - PAE support: %s\n" % instance["hvm_pae"])
685 buf.write(" - virtual CDROM: %s\n" % instance["hvm_cdrom_image_path"])
686 if instance.has_key("vnc_bind_address"):
687 buf.write(" VNC bind address: %s\n" % instance["vnc_bind_address"])
688 buf.write(" Hardware:\n")
689 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
690 buf.write(" - memory: %dMiB\n" % instance["memory"])
691 buf.write(" - NICs: %s\n" %
692 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
694 for mac, ip, bridge in instance["nics"]]))
695 buf.write(" Block devices:\n")
697 for device in instance["disks"]:
698 _FormatBlockDevInfo(buf, device, 1)
700 logger.ToStdout(buf.getvalue().rstrip('\n'))
704 def SetInstanceParams(opts, args):
705 """Modifies an instance.
707 All parameters take effect only at the next restart of the instance.
710 opts - class with options as members
711 args - list with a single element, the instance name
713 memory - the new memory size
714 vcpus - the new number of cpus
715 mac - the new MAC address of the instance
718 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
719 opts.kernel_path or opts.initrd_path or opts.hvm_boot_order or
720 opts.hvm_acpi or opts.hvm_pae or opts.hvm_cdrom_image_path or
721 opts.vnc_bind_address):
722 logger.ToStdout("Please give at least one of the parameters.")
725 kernel_path = _TransformPath(opts.kernel_path)
726 initrd_path = _TransformPath(opts.initrd_path)
727 if opts.hvm_boot_order == 'default':
728 hvm_boot_order = constants.VALUE_DEFAULT
730 hvm_boot_order = opts.hvm_boot_order
732 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
733 hvm_pae = opts.hvm_pae == _VALUE_TRUE
735 if ((opts.hvm_cdrom_image_path is not None) and
736 (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)):
737 hvm_cdrom_image_path = None
739 hvm_cdrom_image_path = opts.hvm_cdrom_image_path
741 op = opcodes.OpSetInstanceParams(instance_name=args[0], mem=opts.mem,
742 vcpus=opts.vcpus, ip=opts.ip,
743 bridge=opts.bridge, mac=opts.mac,
744 kernel_path=opts.kernel_path,
745 initrd_path=opts.initrd_path,
746 hvm_boot_order=hvm_boot_order,
747 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
748 hvm_cdrom_image_path=hvm_cdrom_image_path,
749 vnc_bind_address=opts.vnc_bind_address)
751 result = SubmitOpCode(op)
754 logger.ToStdout("Modified instance %s" % args[0])
755 for param, data in result:
756 logger.ToStdout(" - %-5s -> %s" % (param, data))
757 logger.ToStdout("Please don't forget that these parameters take effect"
758 " only at the next start of the instance.")
762 # options used in more than one cmd
763 node_opt = make_option("-n", "--node", dest="node", help="Target node",
766 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
769 # multi-instance selection options
770 m_force_multi = make_option("--force-multiple", dest="force_multi",
771 help="Do not ask for confirmation when more than"
772 " one instance is affected",
773 action="store_true", default=False)
775 m_pri_node_opt = make_option("--primary", dest="multi_mode",
776 help="Filter by nodes (primary only)",
777 const=_SHUTDOWN_NODES_PRI, action="store_const")
779 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
780 help="Filter by nodes (secondary only)",
781 const=_SHUTDOWN_NODES_SEC, action="store_const")
783 m_node_opt = make_option("--node", dest="multi_mode",
784 help="Filter by nodes (primary and secondary)",
785 const=_SHUTDOWN_NODES_BOTH, action="store_const")
787 m_clust_opt = make_option("--all", dest="multi_mode",
788 help="Select all instances in the cluster",
789 const=_SHUTDOWN_CLUSTER, action="store_const")
791 m_inst_opt = make_option("--instance", dest="multi_mode",
792 help="Filter by instance name [default]",
793 const=_SHUTDOWN_INSTANCES, action="store_const")
796 # this is defined separately due to readability only
799 make_option("-n", "--node", dest="node",
800 help="Target node and optional secondary node",
801 metavar="<pnode>[:<snode>]"),
802 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
804 default=20 * 1024, type="unit", metavar="<size>"),
805 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
807 default=4 * 1024, type="unit", metavar="<size>"),
809 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
810 default=128, type="unit", metavar="<mem>"),
811 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
812 default=1, type="int", metavar="<PROC>"),
813 make_option("-t", "--disk-template", dest="disk_template",
814 help="Custom disk setup (diskless, file, plain or drbd)",
815 default=None, metavar="TEMPL"),
816 make_option("-i", "--ip", dest="ip",
817 help="IP address ('none' [default], 'auto', or specify address)",
818 default='none', type="string", metavar="<ADDRESS>"),
819 make_option("--mac", dest="mac",
820 help="MAC address ('auto' [default], or specify address)",
821 default='auto', type="string", metavar="<MACADDRESS>"),
822 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
823 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
824 make_option("-b", "--bridge", dest="bridge",
825 help="Bridge to connect this instance to",
826 default=None, metavar="<bridge>"),
827 make_option("--no-start", dest="start", default=True,
828 action="store_false", help="Don't start the instance after"
830 make_option("--no-ip-check", dest="ip_check", default=True,
831 action="store_false", help="Don't check that the instance's IP"
832 " is alive (only valid with --no-start)"),
833 make_option("--kernel", dest="kernel_path",
834 help="Path to the instances' kernel (or 'default')",
836 type="string", metavar="<FILENAME>"),
837 make_option("--initrd", dest="initrd_path",
838 help="Path to the instances' initrd (or 'none', or 'default')",
840 type="string", metavar="<FILENAME>"),
841 make_option("--hvm-boot-order", dest="hvm_boot_order",
842 help="Boot device order for HVM (one or more of [acdn])",
843 default=None, type="string", metavar="<BOOTORDER>"),
844 make_option("--file-storage-dir", dest="file_storage_dir",
845 help="Relative path under default cluster-wide file storage dir"
846 " to store file-based disks", default=None,
848 make_option("--file-driver", dest="file_driver", help="Driver to use"
849 " for image files", default="loop", metavar="<DRIVER>"),
850 make_option("--iallocator", metavar="<NAME>",
851 help="Select nodes for the instance automatically using the"
852 " <NAME> iallocator plugin", default=None, type="string"),
853 make_option("--hvm-acpi", dest="hvm_acpi",
854 help="ACPI support for HVM (true|false)",
855 metavar="<BOOL>", choices=["true", "false"]),
856 make_option("--hvm-pae", dest="hvm_pae",
857 help="PAE support for HVM (true|false)",
858 metavar="<BOOL>", choices=["true", "false"]),
859 make_option("--hvm-cdrom-image-path", dest="hvm_cdrom_image_path",
860 help="CDROM image path for HVM (absolute path or None)",
861 default=None, type="string", metavar="<CDROMIMAGE>"),
862 make_option("--vnc-bind-address", dest="vnc_bind_address",
863 help="bind address for VNC (IP address)",
864 default=None, type="string", metavar="<VNCADDRESS>"),
868 'add': (AddInstance, ARGS_ONE, add_opts,
869 "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
870 "Creates and adds a new instance to the cluster"),
871 'console': (ConnectToInstanceConsole, ARGS_ONE,
873 make_option("--show-cmd", dest="show_command",
874 action="store_true", default=False,
875 help=("Show command instead of executing it"))],
876 "[--show-cmd] <instance>",
877 "Opens a console on the specified instance"),
878 'failover': (FailoverInstance, ARGS_ONE,
879 [DEBUG_OPT, FORCE_OPT,
880 make_option("--ignore-consistency", dest="ignore_consistency",
881 action="store_true", default=False,
882 help="Ignore the consistency of the disks on"
886 "Stops the instance and starts it on the backup node, using"
887 " the remote mirror (only for instances of type drbd)"),
888 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
889 "Show information on the specified instance"),
890 'list': (ListInstances, ARGS_NONE,
891 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "",
892 "Lists the instances and their status. The available fields are"
893 " (see the man page for details): status, oper_state, oper_ram,"
894 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
895 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
896 " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
898 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
899 "[-f] <instance>", "Reinstall a stopped instance"),
900 'remove': (RemoveInstance, ARGS_ONE,
901 [DEBUG_OPT, FORCE_OPT,
902 make_option("--ignore-failures", dest="ignore_failures",
903 action="store_true", default=False,
904 help=("Remove the instance from the cluster even"
905 " if there are failures during the removal"
906 " process (shutdown, disk removal, etc.)")),
908 "[-f] <instance>", "Shuts down the instance and removes it"),
909 'rename': (RenameInstance, ARGS_FIXED(2),
911 make_option("--no-ip-check", dest="ignore_ip",
912 help="Do not check that the IP of the new name"
914 default=False, action="store_true"),
916 "<instance> <new_name>", "Rename the instance"),
917 'replace-disks': (ReplaceDisks, ARGS_ONE,
919 make_option("-n", "--new-secondary", dest="new_secondary",
920 help=("New secondary node (for secondary"
921 " node change)"), metavar="NODE"),
922 make_option("-p", "--on-primary", dest="on_primary",
923 default=False, action="store_true",
924 help=("Replace the disk(s) on the primary"
925 " node (only for the drbd template)")),
926 make_option("-s", "--on-secondary", dest="on_secondary",
927 default=False, action="store_true",
928 help=("Replace the disk(s) on the secondary"
929 " node (only for the drbd template)")),
930 make_option("--disks", dest="disks", default=None,
931 help=("Comma-separated list of disks"
932 " to replace (e.g. sda) (optional,"
933 " defaults to all disks")),
934 make_option("--iallocator", metavar="<NAME>",
935 help="Select new secondary for the instance"
936 " automatically using the"
937 " <NAME> iallocator plugin (enables"
938 " secondary node replacement)",
939 default=None, type="string"),
941 "[-s|-p|-n NODE] <instance>",
942 "Replaces all disks for the instance"),
943 'modify': (SetInstanceParams, ARGS_ONE,
944 [DEBUG_OPT, FORCE_OPT,
945 cli_option("-m", "--memory", dest="mem",
947 default=None, type="unit", metavar="<mem>"),
948 make_option("-p", "--cpu", dest="vcpus",
949 help="Number of virtual CPUs",
950 default=None, type="int", metavar="<PROC>"),
951 make_option("-i", "--ip", dest="ip",
952 help="IP address ('none' or numeric IP)",
953 default=None, type="string", metavar="<ADDRESS>"),
954 make_option("-b", "--bridge", dest="bridge",
955 help="Bridge to connect this instance to",
956 default=None, type="string", metavar="<bridge>"),
957 make_option("--mac", dest="mac",
958 help="MAC address", default=None,
959 type="string", metavar="<MACADDRESS>"),
960 make_option("--kernel", dest="kernel_path",
961 help="Path to the instances' kernel (or"
962 " 'default')", default=None,
963 type="string", metavar="<FILENAME>"),
964 make_option("--initrd", dest="initrd_path",
965 help="Path to the instances' initrd (or 'none', or"
966 " 'default')", default=None,
967 type="string", metavar="<FILENAME>"),
968 make_option("--hvm-boot-order", dest="hvm_boot_order",
969 help="boot device order for HVM"
970 "(either one or more of [acdn] or 'default')",
971 default=None, type="string", metavar="<BOOTORDER>"),
972 make_option("--hvm-acpi", dest="hvm_acpi",
973 help="ACPI support for HVM (true|false)",
974 metavar="<BOOL>", choices=["true", "false"]),
975 make_option("--hvm-pae", dest="hvm_pae",
976 help="PAE support for HVM (true|false)",
977 metavar="<BOOL>", choices=["true", "false"]),
978 make_option("--hvm-cdrom-image-path",
979 dest="hvm_cdrom_image_path",
980 help="CDROM image path for HVM"
981 "(absolute path or None)",
982 default=None, type="string", metavar="<CDROMIMAGE>"),
983 make_option("--vnc-bind-address", dest="vnc_bind_address",
984 help="bind address for VNC (IP address)",
985 default=None, type="string", metavar="<VNCADDRESS>"),
987 "<instance>", "Alters the parameters of an instance"),
988 'shutdown': (ShutdownInstance, ARGS_ANY,
989 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
990 m_clust_opt, m_inst_opt, m_force_multi],
991 "<instance>", "Stops an instance"),
992 'startup': (StartupInstance, ARGS_ANY,
993 [DEBUG_OPT, FORCE_OPT, m_force_multi,
994 make_option("-e", "--extra", dest="extra_args",
995 help="Extra arguments for the instance's kernel",
996 default=None, type="string", metavar="<PARAMS>"),
997 m_node_opt, m_pri_node_opt, m_sec_node_opt,
998 m_clust_opt, m_inst_opt,
1000 "<instance>", "Starts an instance"),
1002 'reboot': (RebootInstance, ARGS_ANY,
1003 [DEBUG_OPT, m_force_multi,
1004 make_option("-e", "--extra", dest="extra_args",
1005 help="Extra arguments for the instance's kernel",
1006 default=None, type="string", metavar="<PARAMS>"),
1007 make_option("-t", "--type", dest="reboot_type",
1008 help="Type of reboot: soft/hard/full",
1009 default=constants.INSTANCE_REBOOT_SOFT,
1010 type="string", metavar="<REBOOT>"),
1011 make_option("--ignore-secondaries", dest="ignore_secondaries",
1012 default=False, action="store_true",
1013 help="Ignore errors from secondaries"),
1014 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1015 m_clust_opt, m_inst_opt,
1017 "<instance>", "Reboots an instance"),
1018 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
1020 "Activate an instance's disks"),
1021 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
1023 "Deactivate an instance's disks"),
1024 'grow-disk': (GrowDisk, ARGS_FIXED(3), [DEBUG_OPT],
1025 "<instance> <disk> <size>", "Grow an instance's disk"),
1026 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
1027 "<node_name>", "List the tags of the given instance"),
1028 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1029 "<node_name> tag...", "Add tags to the given instance"),
1030 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1031 "<node_name> tag...", "Remove tags from given instance"),
1035 'activate_block_devs': 'activate-disks',
1036 'replace_disks': 'replace-disks',
1041 if __name__ == '__main__':
1042 sys.exit(GenericMain(commands, aliases=aliases,
1043 override={"tag_type": constants.TAG_INSTANCE}))