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,
289 hvm_nic_type=opts.hvm_nic_type,
290 hvm_disk_type=opts.hvm_disk_type)
296 def ReinstallInstance(opts, args):
297 """Reinstall an instance.
300 opts - class with options as members
301 args - list containing a single element, the instance name
304 instance_name = args[0]
307 usertext = ("This will reinstall the instance %s and remove"
308 " all data. Continue?") % instance_name
309 if not AskUser(usertext):
312 op = opcodes.OpReinstallInstance(instance_name=instance_name,
319 def RemoveInstance(opts, args):
320 """Remove an instance.
323 opts - class with options as members
324 args - list containing a single element, the instance name
327 instance_name = args[0]
331 usertext = ("This will remove the volumes of the instance %s"
332 " (including mirrors), thus removing all the data"
333 " of the instance. Continue?") % instance_name
334 if not AskUser(usertext):
337 op = opcodes.OpRemoveInstance(instance_name=instance_name,
338 ignore_failures=opts.ignore_failures)
343 def RenameInstance(opts, args):
344 """Rename an instance.
347 opts - class with options as members
348 args - list containing two elements, the instance name and the new name
351 op = opcodes.OpRenameInstance(instance_name=args[0],
353 ignore_ip=opts.ignore_ip)
359 def ActivateDisks(opts, args):
360 """Activate an instance's disks.
362 This serves two purposes:
363 - it allows one (as long as the instance is not running) to mount
364 the disks and modify them from the node
365 - it repairs inactive secondary drbds
368 instance_name = args[0]
369 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
370 disks_info = SubmitOpCode(op)
371 for host, iname, nname in disks_info:
372 print "%s:%s:%s" % (host, iname, nname)
376 def DeactivateDisks(opts, args):
377 """Command-line interface for _ShutdownInstanceBlockDevices.
379 This function takes the instance name, looks for its primary node
380 and the tries to shutdown its block devices on that node.
383 instance_name = args[0]
384 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
389 def GrowDisk(opts, args):
390 """Command-line interface for _ShutdownInstanceBlockDevices.
392 This function takes the instance name, looks for its primary node
393 and the tries to shutdown its block devices on that node.
398 amount = utils.ParseUnit(args[2])
399 op = opcodes.OpGrowDisk(instance_name=instance, disk=disk, amount=amount)
404 def StartupInstance(opts, args):
405 """Startup an instance.
408 opts - class with options as members
409 args - list containing a single element, the instance name
412 if opts.multi_mode is None:
413 opts.multi_mode = _SHUTDOWN_INSTANCES
414 inames = _ExpandMultiNames(opts.multi_mode, args)
416 raise errors.OpPrereqError("Selection filter does not match any instances")
417 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
418 if not (opts.force_multi or not multi_on
419 or _ConfirmOperation(inames, "startup")):
422 op = opcodes.OpStartupInstance(instance_name=name,
424 extra_args=opts.extra_args)
426 logger.ToStdout("Starting up %s" % name)
431 def RebootInstance(opts, args):
432 """Reboot an instance
435 opts - class with options as members
436 args - list containing a single element, the instance name
439 if opts.multi_mode is None:
440 opts.multi_mode = _SHUTDOWN_INSTANCES
441 inames = _ExpandMultiNames(opts.multi_mode, args)
443 raise errors.OpPrereqError("Selection filter does not match any instances")
444 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
445 if not (opts.force_multi or not multi_on
446 or _ConfirmOperation(inames, "reboot")):
449 op = opcodes.OpRebootInstance(instance_name=name,
450 reboot_type=opts.reboot_type,
451 ignore_secondaries=opts.ignore_secondaries)
457 def ShutdownInstance(opts, args):
458 """Shutdown an instance.
461 opts - class with options as members
462 args - list containing a single element, the instance name
465 if opts.multi_mode is None:
466 opts.multi_mode = _SHUTDOWN_INSTANCES
467 inames = _ExpandMultiNames(opts.multi_mode, args)
469 raise errors.OpPrereqError("Selection filter does not match any instances")
470 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
471 if not (opts.force_multi or not multi_on
472 or _ConfirmOperation(inames, "shutdown")):
475 op = opcodes.OpShutdownInstance(instance_name=name)
477 logger.ToStdout("Shutting down %s" % name)
482 def ReplaceDisks(opts, args):
483 """Replace the disks of an instance
486 opts - class with options as members
487 args - list with a single element, the instance name
490 instance_name = args[0]
491 new_2ndary = opts.new_secondary
492 iallocator = opts.iallocator
493 if opts.disks is None:
494 disks = ["sda", "sdb"]
496 disks = opts.disks.split(",")
497 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
498 mode = constants.REPLACE_DISK_ALL
499 elif opts.on_primary: # only on primary:
500 mode = constants.REPLACE_DISK_PRI
501 if new_2ndary is not None or iallocator is not None:
502 raise errors.OpPrereqError("Can't change secondary node on primary disk"
504 elif opts.on_secondary is not None or iallocator is not None:
506 mode = constants.REPLACE_DISK_SEC
508 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
509 remote_node=new_2ndary, mode=mode,
510 iallocator=iallocator)
515 def FailoverInstance(opts, args):
516 """Failover an instance.
518 The failover is done by shutting it down on its present node and
519 starting it on the secondary.
522 opts - class with options as members
523 args - list with a single element, the instance name
525 force - whether to failover without asking questions.
528 instance_name = args[0]
532 usertext = ("Failover will happen to image %s."
533 " This requires a shutdown of the instance. Continue?" %
535 if not AskUser(usertext):
538 op = opcodes.OpFailoverInstance(instance_name=instance_name,
539 ignore_consistency=opts.ignore_consistency)
544 def ConnectToInstanceConsole(opts, args):
545 """Connect to the console of an instance.
548 opts - class with options as members
549 args - list with a single element, the instance name
552 instance_name = args[0]
554 op = opcodes.OpConnectConsole(instance_name=instance_name)
555 cmd = SubmitOpCode(op)
557 if opts.show_command:
558 print utils.ShellQuoteArgs(cmd)
561 os.execvp(cmd[0], cmd)
563 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
564 (cmd, " ".join(argv)))
568 def _FormatBlockDevInfo(buf, dev, indent_level):
569 """Show block device information.
571 This is only used by ShowInstanceConfig(), but it's too big to be
572 left for an inline definition.
575 def helper(buf, dtype, status):
576 """Format one line for physical device status."""
578 buf.write("not active\n")
580 (path, major, minor, syncp, estt, degr, ldisk) = status
584 major_string = str(major)
589 minor_string = str(minor)
591 buf.write("%s (%s:%s)" % (path, major_string, minor_string))
592 if dtype in (constants.LD_DRBD8, ):
593 if syncp is not None:
594 sync_text = "*RECOVERING* %5.2f%%," % syncp
596 sync_text += " ETA %ds" % estt
598 sync_text += " ETA unknown"
600 sync_text = "in sync"
602 degr_text = "*DEGRADED*"
606 ldisk_text = " *MISSING DISK*"
609 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
610 elif dtype == constants.LD_LV:
612 ldisk_text = " *FAILED* (failed drive?)"
615 buf.write(ldisk_text)
618 if dev["iv_name"] is not None:
619 data = " - %s, " % dev["iv_name"]
622 data += "type: %s" % dev["dev_type"]
623 if dev["logical_id"] is not None:
624 data += ", logical_id: %s" % (dev["logical_id"],)
625 elif dev["physical_id"] is not None:
626 data += ", physical_id: %s" % (dev["physical_id"],)
627 buf.write("%*s%s\n" % (2*indent_level, "", data))
628 buf.write("%*s primary: " % (2*indent_level, ""))
629 helper(buf, dev["dev_type"], dev["pstatus"])
632 buf.write("%*s secondary: " % (2*indent_level, ""))
633 helper(buf, dev["dev_type"], dev["sstatus"])
636 for child in dev["children"]:
637 _FormatBlockDevInfo(buf, child, indent_level+1)
640 def ShowInstanceConfig(opts, args):
641 """Compute instance run-time status.
645 op = opcodes.OpQueryInstanceData(instances=args)
646 result = SubmitOpCode(op)
647 hvm_parameters = ("hvm_acpi", "hvm_pae", "hvm_cdrom_image_path",
648 "hvm_boot_order", "hvm_nic_type", "hvm_disk_type")
650 pvm_parameters = ("kernel_path", "initrd_path")
653 logger.ToStdout("No instances.")
658 for instance_name in result:
659 instance = result[instance_name]
660 buf.write("Instance name: %s\n" % instance["name"])
661 buf.write("State: configured to be %s, actual state is %s\n" %
662 (instance["config_state"], instance["run_state"]))
663 buf.write(" Nodes:\n")
664 buf.write(" - primary: %s\n" % instance["pnode"])
665 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
666 buf.write(" Operating system: %s\n" % instance["os"])
667 if instance.has_key("network_port"):
668 buf.write(" Allocated network port: %s\n" % instance["network_port"])
669 if False not in map(instance.has_key, pvm_parameters):
670 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
671 kpath = "(default: %s)" % constants.XEN_KERNEL
673 kpath = instance["kernel_path"]
674 buf.write(" Kernel path: %s\n" % kpath)
675 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
676 initrd = "(default: %s)" % constants.XEN_INITRD
677 elif instance["initrd_path"] == constants.VALUE_NONE:
680 initrd = instance["initrd_path"]
681 buf.write(" initrd: %s\n" % initrd)
682 if False not in map(instance.has_key, hvm_parameters):
684 buf.write(" - boot order: %s\n" % instance["hvm_boot_order"])
685 buf.write(" - ACPI support: %s\n" % instance["hvm_acpi"])
686 buf.write(" - PAE support: %s\n" % instance["hvm_pae"])
687 buf.write(" - virtual CDROM: %s\n" % instance["hvm_cdrom_image_path"])
688 buf.write(" - virtual NIC type: %s\n" % instance["hvm_nic_type"])
689 buf.write(" - virtual disk type: %s\n" % instance["hvm_disk_type"])
690 if instance.has_key("vnc_bind_address"):
691 buf.write(" VNC bind address: %s\n" % instance["vnc_bind_address"])
692 buf.write(" VNC console port: %s\n" % instance["vnc_console_port"])
693 buf.write(" Hardware:\n")
694 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
695 buf.write(" - memory: %dMiB\n" % instance["memory"])
696 buf.write(" - NICs: %s\n" %
697 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
699 for mac, ip, bridge in instance["nics"]]))
700 buf.write(" Block devices:\n")
702 for device in instance["disks"]:
703 _FormatBlockDevInfo(buf, device, 1)
705 logger.ToStdout(buf.getvalue().rstrip('\n'))
709 def SetInstanceParams(opts, args):
710 """Modifies an instance.
712 All parameters take effect only at the next restart of the instance.
715 opts - class with options as members
716 args - list with a single element, the instance name
718 memory - the new memory size
719 vcpus - the new number of cpus
720 mac - the new MAC address of the instance
723 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
724 opts.kernel_path or opts.initrd_path or opts.hvm_boot_order or
725 opts.hvm_acpi or opts.hvm_pae or opts.hvm_cdrom_image_path or
726 opts.vnc_bind_address or opts.hvm_nic_type or opts.hvm_disk_type):
727 logger.ToStdout("Please give at least one of the parameters.")
730 kernel_path = _TransformPath(opts.kernel_path)
731 initrd_path = _TransformPath(opts.initrd_path)
732 if opts.hvm_boot_order == 'default':
733 hvm_boot_order = constants.VALUE_DEFAULT
735 hvm_boot_order = opts.hvm_boot_order
737 if opts.hvm_acpi is None:
738 hvm_acpi = opts.hvm_acpi
740 hvm_acpi = opts.hvm_acpi == _VALUE_TRUE
742 if opts.hvm_pae is None:
743 hvm_pae = opts.hvm_pae
745 hvm_pae = opts.hvm_pae == _VALUE_TRUE
747 if opts.hvm_nic_type == constants.VALUE_NONE:
750 hvm_nic_type = opts.hvm_nic_type
752 if opts.hvm_disk_type == constants.VALUE_NONE:
755 hvm_disk_type = opts.hvm_disk_type
757 op = opcodes.OpSetInstanceParams(instance_name=args[0], mem=opts.mem,
758 vcpus=opts.vcpus, ip=opts.ip,
759 bridge=opts.bridge, mac=opts.mac,
760 kernel_path=opts.kernel_path,
761 initrd_path=opts.initrd_path,
762 hvm_boot_order=hvm_boot_order,
763 hvm_acpi=hvm_acpi, hvm_pae=hvm_pae,
764 hvm_cdrom_image_path=
765 opts.hvm_cdrom_image_path,
766 vnc_bind_address=opts.vnc_bind_address,
767 hvm_nic_type=hvm_nic_type,
768 hvm_disk_type=hvm_disk_type,
771 result = SubmitOpCode(op)
774 logger.ToStdout("Modified instance %s" % args[0])
775 for param, data in result:
776 logger.ToStdout(" - %-5s -> %s" % (param, data))
777 logger.ToStdout("Please don't forget that these parameters take effect"
778 " only at the next start of the instance.")
782 # options used in more than one cmd
783 node_opt = make_option("-n", "--node", dest="node", help="Target node",
786 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
789 # multi-instance selection options
790 m_force_multi = make_option("--force-multiple", dest="force_multi",
791 help="Do not ask for confirmation when more than"
792 " one instance is affected",
793 action="store_true", default=False)
795 m_pri_node_opt = make_option("--primary", dest="multi_mode",
796 help="Filter by nodes (primary only)",
797 const=_SHUTDOWN_NODES_PRI, action="store_const")
799 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
800 help="Filter by nodes (secondary only)",
801 const=_SHUTDOWN_NODES_SEC, action="store_const")
803 m_node_opt = make_option("--node", dest="multi_mode",
804 help="Filter by nodes (primary and secondary)",
805 const=_SHUTDOWN_NODES_BOTH, action="store_const")
807 m_clust_opt = make_option("--all", dest="multi_mode",
808 help="Select all instances in the cluster",
809 const=_SHUTDOWN_CLUSTER, action="store_const")
811 m_inst_opt = make_option("--instance", dest="multi_mode",
812 help="Filter by instance name [default]",
813 const=_SHUTDOWN_INSTANCES, action="store_const")
816 # this is defined separately due to readability only
819 make_option("-n", "--node", dest="node",
820 help="Target node and optional secondary node",
821 metavar="<pnode>[:<snode>]"),
822 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
824 default=20 * 1024, type="unit", metavar="<size>"),
825 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
827 default=4 * 1024, type="unit", metavar="<size>"),
829 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
830 default=128, type="unit", metavar="<mem>"),
831 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
832 default=1, type="int", metavar="<PROC>"),
833 make_option("-t", "--disk-template", dest="disk_template",
834 help="Custom disk setup (diskless, file, plain or drbd)",
835 default=None, metavar="TEMPL"),
836 make_option("-i", "--ip", dest="ip",
837 help="IP address ('none' [default], 'auto', or specify address)",
838 default='none', type="string", metavar="<ADDRESS>"),
839 make_option("--mac", dest="mac",
840 help="MAC address ('auto' [default], or specify address)",
841 default='auto', type="string", metavar="<MACADDRESS>"),
842 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
843 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
844 make_option("-b", "--bridge", dest="bridge",
845 help="Bridge to connect this instance to",
846 default=None, metavar="<bridge>"),
847 make_option("--no-start", dest="start", default=True,
848 action="store_false", help="Don't start the instance after"
850 make_option("--no-ip-check", dest="ip_check", default=True,
851 action="store_false", help="Don't check that the instance's IP"
852 " is alive (only valid with --no-start)"),
853 make_option("--kernel", dest="kernel_path",
854 help="Path to the instances' kernel (or 'default')",
856 type="string", metavar="<FILENAME>"),
857 make_option("--initrd", dest="initrd_path",
858 help="Path to the instances' initrd (or 'none', or 'default')",
860 type="string", metavar="<FILENAME>"),
861 make_option("--hvm-boot-order", dest="hvm_boot_order",
862 help="Boot device order for HVM (one or more of [acdn])",
863 default=None, type="string", metavar="<BOOTORDER>"),
864 make_option("--file-storage-dir", dest="file_storage_dir",
865 help="Relative path under default cluster-wide file storage dir"
866 " to store file-based disks", default=None,
868 make_option("--file-driver", dest="file_driver", help="Driver to use"
869 " for image files", default="loop", metavar="<DRIVER>"),
870 make_option("--iallocator", metavar="<NAME>",
871 help="Select nodes for the instance automatically using the"
872 " <NAME> iallocator plugin", default=None, type="string"),
873 make_option("--hvm-acpi", dest="hvm_acpi",
874 help="ACPI support for HVM (true|false)",
875 metavar="<BOOL>", choices=["true", "false"]),
876 make_option("--hvm-nic-type", dest="hvm_nic_type",
877 help="Type of virtual NIC for HVM "
878 "(rtl8139,ne2k_pci,ne2k_isa,paravirtual)",
879 metavar="NICTYPE", choices=[constants.HT_HVM_NIC_RTL8139,
880 constants.HT_HVM_NIC_NE2K_PCI,
881 constants.HT_HVM_NIC_NE2K_ISA,
882 constants.HT_HVM_DEV_PARAVIRTUAL],
883 default=constants.HT_HVM_NIC_RTL8139),
884 make_option("--hvm-disk-type", dest="hvm_disk_type",
885 help="Type of virtual disks for HVM (ioemu,paravirtual)",
886 metavar="DISKTYPE", choices=[constants.HT_HVM_DEV_IOEMU,
887 constants.HT_HVM_DEV_PARAVIRTUAL],
888 default=constants.HT_HVM_DEV_IOEMU,),
889 make_option("--hvm-pae", dest="hvm_pae",
890 help="PAE support for HVM (true|false)",
891 metavar="<BOOL>", choices=["true", "false"]),
892 make_option("--hvm-cdrom-image-path", dest="hvm_cdrom_image_path",
893 help="CDROM image path for HVM (absolute path or None)",
894 default=None, type="string", metavar="<CDROMIMAGE>"),
895 make_option("--vnc-bind-address", dest="vnc_bind_address",
896 help="bind address for VNC (IP address)",
897 default=None, type="string", metavar="<VNCADDRESS>"),
901 'add': (AddInstance, ARGS_ONE, add_opts,
902 "[...] -t disk-type -n node[:secondary-node] -o os-type <name>",
903 "Creates and adds a new instance to the cluster"),
904 'console': (ConnectToInstanceConsole, ARGS_ONE,
906 make_option("--show-cmd", dest="show_command",
907 action="store_true", default=False,
908 help=("Show command instead of executing it"))],
909 "[--show-cmd] <instance>",
910 "Opens a console on the specified instance"),
911 'failover': (FailoverInstance, ARGS_ONE,
912 [DEBUG_OPT, FORCE_OPT,
913 make_option("--ignore-consistency", dest="ignore_consistency",
914 action="store_true", default=False,
915 help="Ignore the consistency of the disks on"
919 "Stops the instance and starts it on the backup node, using"
920 " the remote mirror (only for instances of type drbd)"),
921 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
922 "Show information on the specified instance"),
923 'list': (ListInstances, ARGS_NONE,
924 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "",
925 "Lists the instances and their status. The available fields are"
926 " (see the man page for details): status, oper_state, oper_ram,"
927 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
928 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
929 " list is (in order): %s." % ", ".join(_LIST_DEF_FIELDS),
931 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
932 "[-f] <instance>", "Reinstall a stopped instance"),
933 'remove': (RemoveInstance, ARGS_ONE,
934 [DEBUG_OPT, FORCE_OPT,
935 make_option("--ignore-failures", dest="ignore_failures",
936 action="store_true", default=False,
937 help=("Remove the instance from the cluster even"
938 " if there are failures during the removal"
939 " process (shutdown, disk removal, etc.)")),
941 "[-f] <instance>", "Shuts down the instance and removes it"),
942 'rename': (RenameInstance, ARGS_FIXED(2),
944 make_option("--no-ip-check", dest="ignore_ip",
945 help="Do not check that the IP of the new name"
947 default=False, action="store_true"),
949 "<instance> <new_name>", "Rename the instance"),
950 'replace-disks': (ReplaceDisks, ARGS_ONE,
952 make_option("-n", "--new-secondary", dest="new_secondary",
953 help=("New secondary node (for secondary"
954 " node change)"), metavar="NODE"),
955 make_option("-p", "--on-primary", dest="on_primary",
956 default=False, action="store_true",
957 help=("Replace the disk(s) on the primary"
958 " node (only for the drbd template)")),
959 make_option("-s", "--on-secondary", dest="on_secondary",
960 default=False, action="store_true",
961 help=("Replace the disk(s) on the secondary"
962 " node (only for the drbd template)")),
963 make_option("--disks", dest="disks", default=None,
964 help=("Comma-separated list of disks"
965 " to replace (e.g. sda) (optional,"
966 " defaults to all disks")),
967 make_option("--iallocator", metavar="<NAME>",
968 help="Select new secondary for the instance"
969 " automatically using the"
970 " <NAME> iallocator plugin (enables"
971 " secondary node replacement)",
972 default=None, type="string"),
974 "[-s|-p|-n NODE] <instance>",
975 "Replaces all disks for the instance"),
976 'modify': (SetInstanceParams, ARGS_ONE,
977 [DEBUG_OPT, FORCE_OPT,
978 cli_option("-m", "--memory", dest="mem",
980 default=None, type="unit", metavar="<mem>"),
981 make_option("-p", "--cpu", dest="vcpus",
982 help="Number of virtual CPUs",
983 default=None, type="int", metavar="<PROC>"),
984 make_option("-i", "--ip", dest="ip",
985 help="IP address ('none' or numeric IP)",
986 default=None, type="string", metavar="<ADDRESS>"),
987 make_option("-b", "--bridge", dest="bridge",
988 help="Bridge to connect this instance to",
989 default=None, type="string", metavar="<bridge>"),
990 make_option("--mac", dest="mac",
991 help="MAC address", default=None,
992 type="string", metavar="<MACADDRESS>"),
993 make_option("--kernel", dest="kernel_path",
994 help="Path to the instances' kernel (or"
995 " 'default')", default=None,
996 type="string", metavar="<FILENAME>"),
997 make_option("--initrd", dest="initrd_path",
998 help="Path to the instances' initrd (or 'none', or"
999 " 'default')", default=None,
1000 type="string", metavar="<FILENAME>"),
1001 make_option("--hvm-boot-order", dest="hvm_boot_order",
1002 help="boot device order for HVM"
1003 "(either one or more of [acdn] or 'default')",
1004 default=None, type="string", metavar="<BOOTORDER>"),
1005 make_option("--hvm-acpi", dest="hvm_acpi",
1006 help="ACPI support for HVM (true|false)",
1007 metavar="<BOOL>", choices=["true", "false"]),
1008 make_option("--hvm-pae", dest="hvm_pae",
1009 help="PAE support for HVM (true|false)",
1010 metavar="<BOOL>", choices=["true", "false"]),
1011 make_option("--hvm-cdrom-image-path",
1012 dest="hvm_cdrom_image_path",
1013 help="CDROM image path for HVM"
1014 "(absolute path or None)",
1015 default=None, type="string", metavar="<CDROMIMAGE>"),
1016 make_option("--hvm-nic-type", dest="hvm_nic_type",
1017 help="Type of virtual NIC for HVM "
1018 "(rtl8139,ne2k_pci,ne2k_isa,paravirtual)",
1020 choices=[constants.HT_HVM_NIC_RTL8139,
1021 constants.HT_HVM_NIC_NE2K_PCI,
1022 constants.HT_HVM_NIC_NE2K_ISA,
1023 constants.HT_HVM_DEV_PARAVIRTUAL],
1025 make_option("--hvm-disk-type", dest="hvm_disk_type",
1026 help="Type of virtual disks for HVM "
1027 "(ioemu,paravirtual)",
1029 choices=[constants.HT_HVM_DEV_IOEMU,
1030 constants.HT_HVM_DEV_PARAVIRTUAL],
1032 make_option("--vnc-bind-address", dest="vnc_bind_address",
1033 help="bind address for VNC (IP address)",
1034 default=None, type="string", metavar="<VNCADDRESS>"),
1036 "<instance>", "Alters the parameters of an instance"),
1037 'shutdown': (ShutdownInstance, ARGS_ANY,
1038 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
1039 m_clust_opt, m_inst_opt, m_force_multi],
1040 "<instance>", "Stops an instance"),
1041 'startup': (StartupInstance, ARGS_ANY,
1042 [DEBUG_OPT, FORCE_OPT, m_force_multi,
1043 make_option("-e", "--extra", dest="extra_args",
1044 help="Extra arguments for the instance's kernel",
1045 default=None, type="string", metavar="<PARAMS>"),
1046 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1047 m_clust_opt, m_inst_opt,
1049 "<instance>", "Starts an instance"),
1051 'reboot': (RebootInstance, ARGS_ANY,
1052 [DEBUG_OPT, m_force_multi,
1053 make_option("-e", "--extra", dest="extra_args",
1054 help="Extra arguments for the instance's kernel",
1055 default=None, type="string", metavar="<PARAMS>"),
1056 make_option("-t", "--type", dest="reboot_type",
1057 help="Type of reboot: soft/hard/full",
1058 default=constants.INSTANCE_REBOOT_SOFT,
1059 type="string", metavar="<REBOOT>"),
1060 make_option("--ignore-secondaries", dest="ignore_secondaries",
1061 default=False, action="store_true",
1062 help="Ignore errors from secondaries"),
1063 m_node_opt, m_pri_node_opt, m_sec_node_opt,
1064 m_clust_opt, m_inst_opt,
1066 "<instance>", "Reboots an instance"),
1067 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
1069 "Activate an instance's disks"),
1070 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
1072 "Deactivate an instance's disks"),
1073 'grow-disk': (GrowDisk, ARGS_FIXED(3), [DEBUG_OPT],
1074 "<instance> <disk> <size>", "Grow an instance's disk"),
1075 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
1076 "<node_name>", "List the tags of the given instance"),
1077 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1078 "<node_name> tag...", "Add tags to the given instance"),
1079 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
1080 "<node_name> tag...", "Remove tags from given instance"),
1084 'activate_block_devs': 'activate-disks',
1085 'replace_disks': 'replace-disks',
1090 if __name__ == '__main__':
1091 sys.exit(GenericMain(commands, aliases=aliases,
1092 override={"tag_type": constants.TAG_INSTANCE}))