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 output = GetClient().QueryInstances([], selected_fields)
181 if not opts.no_headers:
183 "name": "Instance", "os": "OS", "pnode": "Primary_node",
184 "snodes": "Secondary_Nodes", "admin_state": "Autostart",
185 "oper_state": "Running", "admin_ram": "Configured_memory",
186 "oper_ram": "Memory", "disk_template": "Disk_template",
187 "ip": "IP Address", "mac": "MAC Address",
188 "bridge": "Bridge", "vcpus": "VCPUs",
189 "sda_size": "Disk/0", "sdb_size": "Disk/1",
190 "status": "Status", "tags": "Tags",
195 if opts.human_readable:
196 unitfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
200 numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size", "vcpus"]
202 list_type_fields = ("tags",)
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":
227 elif field in list_type_fields:
231 data = GenerateTable(separator=opts.separator, headers=headers,
232 fields=selected_fields, unitfields=unitfields,
233 numfields=numfields, data=output)
236 logger.ToStdout(line)
241 def AddInstance(opts, args):
242 """Add an instance to the cluster.
245 opts - class with options as members
246 args - list with a single element, the instance name
248 mem - amount of memory to allocate to instance (MiB)
249 size - amount of disk space to allocate to instance (MiB)
250 os - which OS to run on instance
251 node - node to run new instance on
256 (pnode, snode) = SplitNodeOption(opts.node)
258 kernel_path = _TransformPath(opts.kernel_path)
259 initrd_path = _TransformPath(opts.initrd_path)
261 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
262 hvm_pae = opts.hvm_pae == _VALUE_TRUE
264 if ((opts.hvm_cdrom_image_path is not None) and
265 (opts.hvm_cdrom_image_path.lower() == constants.VALUE_NONE)):
266 hvm_cdrom_image_path = None
268 hvm_cdrom_image_path = opts.hvm_cdrom_image_path
270 op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
271 disk_size=opts.size, swap_size=opts.swap,
272 disk_template=opts.disk_template,
273 mode=constants.INSTANCE_CREATE,
274 os_type=opts.os, pnode=pnode,
275 snode=snode, vcpus=opts.vcpus,
276 ip=opts.ip, bridge=opts.bridge,
277 start=opts.start, ip_check=opts.ip_check,
278 wait_for_sync=opts.wait_for_sync,
280 kernel_path=kernel_path,
281 initrd_path=initrd_path,
282 iallocator=opts.iallocator,
283 hvm_boot_order=opts.hvm_boot_order,
284 file_storage_dir=opts.file_storage_dir,
285 file_driver=opts.file_driver,
286 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
287 hvm_cdrom_image_path=hvm_cdrom_image_path,
288 vnc_bind_address=opts.vnc_bind_address)
294 def ReinstallInstance(opts, args):
295 """Reinstall an instance.
298 opts - class with options as members
299 args - list containing a single element, the instance name
302 instance_name = args[0]
305 usertext = ("This will reinstall the instance %s and remove"
306 " all data. Continue?") % instance_name
307 if not AskUser(usertext):
310 op = opcodes.OpReinstallInstance(instance_name=instance_name,
317 def RemoveInstance(opts, args):
318 """Remove an instance.
321 opts - class with options as members
322 args - list containing a single element, the instance name
325 instance_name = args[0]
329 usertext = ("This will remove the volumes of the instance %s"
330 " (including mirrors), thus removing all the data"
331 " of the instance. Continue?") % instance_name
332 if not AskUser(usertext):
335 op = opcodes.OpRemoveInstance(instance_name=instance_name,
336 ignore_failures=opts.ignore_failures)
341 def RenameInstance(opts, args):
342 """Rename an instance.
345 opts - class with options as members
346 args - list containing two elements, the instance name and the new name
349 op = opcodes.OpRenameInstance(instance_name=args[0],
351 ignore_ip=opts.ignore_ip)
357 def ActivateDisks(opts, args):
358 """Activate an instance's disks.
360 This serves two purposes:
361 - it allows one (as long as the instance is not running) to mount
362 the disks and modify them from the node
363 - it repairs inactive secondary drbds
366 instance_name = args[0]
367 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
368 disks_info = SubmitOpCode(op)
369 for host, iname, nname in disks_info:
370 print "%s:%s:%s" % (host, iname, nname)
374 def DeactivateDisks(opts, args):
375 """Command-line interface for _ShutdownInstanceBlockDevices.
377 This function takes the instance name, looks for its primary node
378 and the tries to shutdown its block devices on that node.
381 instance_name = args[0]
382 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
387 def GrowDisk(opts, args):
388 """Command-line interface for _ShutdownInstanceBlockDevices.
390 This function takes the instance name, looks for its primary node
391 and the tries to shutdown its block devices on that node.
396 amount = utils.ParseUnit(args[2])
397 op = opcodes.OpGrowDisk(instance_name=instance, disk=disk, amount=amount)
402 def StartupInstance(opts, args):
403 """Startup an instance.
406 opts - class with options as members
407 args - list containing a single element, the instance name
410 if opts.multi_mode is None:
411 opts.multi_mode = _SHUTDOWN_INSTANCES
412 inames = _ExpandMultiNames(opts.multi_mode, args)
414 raise errors.OpPrereqError("Selection filter does not match any instances")
415 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
416 if not (opts.force_multi or not multi_on
417 or _ConfirmOperation(inames, "startup")):
420 op = opcodes.OpStartupInstance(instance_name=name,
422 extra_args=opts.extra_args)
424 logger.ToStdout("Starting up %s" % name)
429 def RebootInstance(opts, args):
430 """Reboot an instance
433 opts - class with options as members
434 args - list containing a single element, the instance name
437 if opts.multi_mode is None:
438 opts.multi_mode = _SHUTDOWN_INSTANCES
439 inames = _ExpandMultiNames(opts.multi_mode, args)
441 raise errors.OpPrereqError("Selection filter does not match any instances")
442 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
443 if not (opts.force_multi or not multi_on
444 or _ConfirmOperation(inames, "reboot")):
447 op = opcodes.OpRebootInstance(instance_name=name,
448 reboot_type=opts.reboot_type,
449 ignore_secondaries=opts.ignore_secondaries)
455 def ShutdownInstance(opts, args):
456 """Shutdown an instance.
459 opts - class with options as members
460 args - list containing a single element, the instance name
463 if opts.multi_mode is None:
464 opts.multi_mode = _SHUTDOWN_INSTANCES
465 inames = _ExpandMultiNames(opts.multi_mode, args)
467 raise errors.OpPrereqError("Selection filter does not match any instances")
468 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
469 if not (opts.force_multi or not multi_on
470 or _ConfirmOperation(inames, "shutdown")):
473 op = opcodes.OpShutdownInstance(instance_name=name)
475 logger.ToStdout("Shutting down %s" % name)
480 def ReplaceDisks(opts, args):
481 """Replace the disks of an instance
484 opts - class with options as members
485 args - list with a single element, the instance name
488 instance_name = args[0]
489 new_2ndary = opts.new_secondary
490 iallocator = opts.iallocator
491 if opts.disks is None:
492 disks = ["sda", "sdb"]
494 disks = opts.disks.split(",")
495 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
496 mode = constants.REPLACE_DISK_ALL
497 elif opts.on_primary: # only on primary:
498 mode = constants.REPLACE_DISK_PRI
499 if new_2ndary is not None or iallocator is not None:
500 raise errors.OpPrereqError("Can't change secondary node on primary disk"
502 elif opts.on_secondary is not None or iallocator is not None:
504 mode = constants.REPLACE_DISK_SEC
506 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
507 remote_node=new_2ndary, mode=mode,
508 iallocator=iallocator)
513 def FailoverInstance(opts, args):
514 """Failover an instance.
516 The failover is done by shutting it down on its present node and
517 starting it on the secondary.
520 opts - class with options as members
521 args - list with a single element, the instance name
523 force - whether to failover without asking questions.
526 instance_name = args[0]
530 usertext = ("Failover will happen to image %s."
531 " This requires a shutdown of the instance. Continue?" %
533 if not AskUser(usertext):
536 op = opcodes.OpFailoverInstance(instance_name=instance_name,
537 ignore_consistency=opts.ignore_consistency)
542 def ConnectToInstanceConsole(opts, args):
543 """Connect to the console of an instance.
546 opts - class with options as members
547 args - list with a single element, the instance name
550 instance_name = args[0]
552 op = opcodes.OpConnectConsole(instance_name=instance_name)
553 cmd = SubmitOpCode(op)
555 if opts.show_command:
556 print utils.ShellQuoteArgs(cmd)
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_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 if opts.hvm_acpi is None:
733 hvm_acpi = opts.hvm_acpi
735 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
737 if opts.hvm_pae is None:
738 hvm_pae = opts.hvm_pae
740 hvm_pae = opts.hvm_pae == _VALUE_TRUE
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=
750 opts.hvm_cdrom_image_path,
751 vnc_bind_address=opts.vnc_bind_address)
753 result = SubmitOpCode(op)
756 logger.ToStdout("Modified instance %s" % args[0])
757 for param, data in result:
758 logger.ToStdout(" - %-5s -> %s" % (param, data))
759 logger.ToStdout("Please don't forget that these parameters take effect"
760 " only at the next start of the instance.")
764 # options used in more than one cmd
765 node_opt = make_option("-n", "--node", dest="node", help="Target node",
768 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
771 # multi-instance selection options
772 m_force_multi = make_option("--force-multiple", dest="force_multi",
773 help="Do not ask for confirmation when more than"
774 " one instance is affected",
775 action="store_true", default=False)
777 m_pri_node_opt = make_option("--primary", dest="multi_mode",
778 help="Filter by nodes (primary only)",
779 const=_SHUTDOWN_NODES_PRI, action="store_const")
781 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
782 help="Filter by nodes (secondary only)",
783 const=_SHUTDOWN_NODES_SEC, action="store_const")
785 m_node_opt = make_option("--node", dest="multi_mode",
786 help="Filter by nodes (primary and secondary)",
787 const=_SHUTDOWN_NODES_BOTH, action="store_const")
789 m_clust_opt = make_option("--all", dest="multi_mode",
790 help="Select all instances in the cluster",
791 const=_SHUTDOWN_CLUSTER, action="store_const")
793 m_inst_opt = make_option("--instance", dest="multi_mode",
794 help="Filter by instance name [default]",
795 const=_SHUTDOWN_INSTANCES, action="store_const")
798 # this is defined separately due to readability only
801 make_option("-n", "--node", dest="node",
802 help="Target node and optional secondary node",
803 metavar="<pnode>[:<snode>]"),
804 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
806 default=20 * 1024, type="unit", metavar="<size>"),
807 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
809 default=4 * 1024, type="unit", metavar="<size>"),
811 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
812 default=128, type="unit", metavar="<mem>"),
813 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
814 default=1, type="int", metavar="<PROC>"),
815 make_option("-t", "--disk-template", dest="disk_template",
816 help="Custom disk setup (diskless, file, plain or drbd)",
817 default=None, metavar="TEMPL"),
818 make_option("-i", "--ip", dest="ip",
819 help="IP address ('none' [default], 'auto', or specify address)",
820 default='none', type="string", metavar="<ADDRESS>"),
821 make_option("--mac", dest="mac",
822 help="MAC address ('auto' [default], or specify address)",
823 default='auto', type="string", metavar="<MACADDRESS>"),
824 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
825 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
826 make_option("-b", "--bridge", dest="bridge",
827 help="Bridge to connect this instance to",
828 default=None, metavar="<bridge>"),
829 make_option("--no-start", dest="start", default=True,
830 action="store_false", help="Don't start the instance after"
832 make_option("--no-ip-check", dest="ip_check", default=True,
833 action="store_false", help="Don't check that the instance's IP"
834 " is alive (only valid with --no-start)"),
835 make_option("--kernel", dest="kernel_path",
836 help="Path to the instances' kernel (or 'default')",
838 type="string", metavar="<FILENAME>"),
839 make_option("--initrd", dest="initrd_path",
840 help="Path to the instances' initrd (or 'none', or 'default')",
842 type="string", metavar="<FILENAME>"),
843 make_option("--hvm-boot-order", dest="hvm_boot_order",
844 help="Boot device order for HVM (one or more of [acdn])",
845 default=None, type="string", metavar="<BOOTORDER>"),
846 make_option("--file-storage-dir", dest="file_storage_dir",
847 help="Relative path under default cluster-wide file storage dir"
848 " to store file-based disks", default=None,
850 make_option("--file-driver", dest="file_driver", help="Driver to use"
851 " for image files", default="loop", metavar="<DRIVER>"),
852 make_option("--iallocator", metavar="<NAME>",
853 help="Select nodes for the instance automatically using the"
854 " <NAME> iallocator plugin", default=None, type="string"),
855 make_option("--hvm-acpi", dest="hvm_acpi",
856 help="ACPI support for HVM (true|false)",
857 metavar="<BOOL>", choices=["true", "false"]),
858 make_option("--hvm-pae", dest="hvm_pae",
859 help="PAE support for HVM (true|false)",
860 metavar="<BOOL>", choices=["true", "false"]),
861 make_option("--hvm-cdrom-image-path", dest="hvm_cdrom_image_path",
862 help="CDROM image path for HVM (absolute path or None)",
863 default=None, type="string", metavar="<CDROMIMAGE>"),
864 make_option("--vnc-bind-address", dest="vnc_bind_address",
865 help="bind address for VNC (IP address)",
866 default=None, type="string", metavar="<VNCADDRESS>"),
870 'add': (AddInstance, ARGS_ONE, add_opts,
871 "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
872 "Creates and adds a new instance to the cluster"),
873 'console': (ConnectToInstanceConsole, ARGS_ONE,
875 make_option("--show-cmd", dest="show_command",
876 action="store_true", default=False,
877 help=("Show command instead of executing it"))],
878 "[--show-cmd] <instance>",
879 "Opens a console on the specified instance"),
880 'failover': (FailoverInstance, ARGS_ONE,
881 [DEBUG_OPT, FORCE_OPT,
882 make_option("--ignore-consistency", dest="ignore_consistency",
883 action="store_true", default=False,
884 help="Ignore the consistency of the disks on"
888 "Stops the instance and starts it on the backup node, using"
889 " the remote mirror (only for instances of type drbd)"),
890 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
891 "Show information on the specified instance"),
892 'list': (ListInstances, ARGS_NONE,
893 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "",
894 "Lists the instances and their status. The available fields are"
895 " (see the man page for details): status, oper_state, oper_ram,"
896 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
897 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
898 " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
900 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
901 "[-f] <instance>", "Reinstall a stopped instance"),
902 'remove': (RemoveInstance, ARGS_ONE,
903 [DEBUG_OPT, FORCE_OPT,
904 make_option("--ignore-failures", dest="ignore_failures",
905 action="store_true", default=False,
906 help=("Remove the instance from the cluster even"
907 " if there are failures during the removal"
908 " process (shutdown, disk removal, etc.)")),
910 "[-f] <instance>", "Shuts down the instance and removes it"),
911 'rename': (RenameInstance, ARGS_FIXED(2),
913 make_option("--no-ip-check", dest="ignore_ip",
914 help="Do not check that the IP of the new name"
916 default=False, action="store_true"),
918 "<instance> <new_name>", "Rename the instance"),
919 'replace-disks': (ReplaceDisks, ARGS_ONE,
921 make_option("-n", "--new-secondary", dest="new_secondary",
922 help=("New secondary node (for secondary"
923 " node change)"), metavar="NODE"),
924 make_option("-p", "--on-primary", dest="on_primary",
925 default=False, action="store_true",
926 help=("Replace the disk(s) on the primary"
927 " node (only for the drbd template)")),
928 make_option("-s", "--on-secondary", dest="on_secondary",
929 default=False, action="store_true",
930 help=("Replace the disk(s) on the secondary"
931 " node (only for the drbd template)")),
932 make_option("--disks", dest="disks", default=None,
933 help=("Comma-separated list of disks"
934 " to replace (e.g. sda) (optional,"
935 " defaults to all disks")),
936 make_option("--iallocator", metavar="<NAME>",
937 help="Select new secondary for the instance"
938 " automatically using the"
939 " <NAME> iallocator plugin (enables"
940 " secondary node replacement)",
941 default=None, type="string"),
943 "[-s|-p|-n NODE] <instance>",
944 "Replaces all disks for the instance"),
945 'modify': (SetInstanceParams, ARGS_ONE,
946 [DEBUG_OPT, FORCE_OPT,
947 cli_option("-m", "--memory", dest="mem",
949 default=None, type="unit", metavar="<mem>"),
950 make_option("-p", "--cpu", dest="vcpus",
951 help="Number of virtual CPUs",
952 default=None, type="int", metavar="<PROC>"),
953 make_option("-i", "--ip", dest="ip",
954 help="IP address ('none' or numeric IP)",
955 default=None, type="string", metavar="<ADDRESS>"),
956 make_option("-b", "--bridge", dest="bridge",
957 help="Bridge to connect this instance to",
958 default=None, type="string", metavar="<bridge>"),
959 make_option("--mac", dest="mac",
960 help="MAC address", default=None,
961 type="string", metavar="<MACADDRESS>"),
962 make_option("--kernel", dest="kernel_path",
963 help="Path to the instances' kernel (or"
964 " 'default')", default=None,
965 type="string", metavar="<FILENAME>"),
966 make_option("--initrd", dest="initrd_path",
967 help="Path to the instances' initrd (or 'none', or"
968 " 'default')", default=None,
969 type="string", metavar="<FILENAME>"),
970 make_option("--hvm-boot-order", dest="hvm_boot_order",
971 help="boot device order for HVM"
972 "(either one or more of [acdn] or 'default')",
973 default=None, type="string", metavar="<BOOTORDER>"),
974 make_option("--hvm-acpi", dest="hvm_acpi",
975 help="ACPI support for HVM (true|false)",
976 metavar="<BOOL>", choices=["true", "false"]),
977 make_option("--hvm-pae", dest="hvm_pae",
978 help="PAE support for HVM (true|false)",
979 metavar="<BOOL>", choices=["true", "false"]),
980 make_option("--hvm-cdrom-image-path",
981 dest="hvm_cdrom_image_path",
982 help="CDROM image path for HVM"
983 "(absolute path or None)",
984 default=None, type="string", metavar="<CDROMIMAGE>"),
985 make_option("--vnc-bind-address", dest="vnc_bind_address",
986 help="bind address for VNC (IP address)",
987 default=None, type="string", metavar="<VNCADDRESS>"),
989 "<instance>", "Alters the parameters of an instance"),
990 'shutdown': (ShutdownInstance, ARGS_ANY,
991 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
992 m_clust_opt, m_inst_opt, m_force_multi],
993 "<instance>", "Stops an instance"),
994 'startup': (StartupInstance, ARGS_ANY,
995 [DEBUG_OPT, FORCE_OPT, m_force_multi,
996 make_option("-e", "--extra", dest="extra_args",
997 help="Extra arguments for the instance's kernel",
998 default=None, type="string", metavar="<PARAMS>"),
999 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1000 m_clust_opt, m_inst_opt,
1002 "<instance>", "Starts an instance"),
1004 'reboot': (RebootInstance, ARGS_ANY,
1005 [DEBUG_OPT, m_force_multi,
1006 make_option("-e", "--extra", dest="extra_args",
1007 help="Extra arguments for the instance's kernel",
1008 default=None, type="string", metavar="<PARAMS>"),
1009 make_option("-t", "--type", dest="reboot_type",
1010 help="Type of reboot: soft/hard/full",
1011 default=constants.INSTANCE_REBOOT_SOFT,
1012 type="string", metavar="<REBOOT>"),
1013 make_option("--ignore-secondaries", dest="ignore_secondaries",
1014 default=False, action="store_true",
1015 help="Ignore errors from secondaries"),
1016 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1017 m_clust_opt, m_inst_opt,
1019 "<instance>", "Reboots an instance"),
1020 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
1022 "Activate an instance's disks"),
1023 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
1025 "Deactivate an instance's disks"),
1026 'grow-disk': (GrowDisk, ARGS_FIXED(3), [DEBUG_OPT],
1027 "<instance> <disk> <size>", "Grow an instance's disk"),
1028 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
1029 "<node_name>", "List the tags of the given instance"),
1030 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1031 "<node_name> tag...", "Add tags to the given instance"),
1032 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1033 "<node_name> tag...", "Remove tags from given instance"),
1037 'activate_block_devs': 'activate-disks',
1038 'replace_disks': 'replace-disks',
1043 if __name__ == '__main__':
1044 sys.exit(GenericMain(commands, aliases=aliases,
1045 override={"tag_type": constants.TAG_INSTANCE}))