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"
43 def _ExpandMultiNames(mode, names):
44 """Expand the given names using the passed mode.
47 - mode, which can be one of _SHUTDOWN_CLUSTER, _SHUTDOWN_NODES_BOTH,
48 _SHUTDOWN_NODES_PRI, _SHUTDOWN_NODES_SEC or _SHUTDOWN_INSTANCES
49 - names, which is a list of names; for cluster, it must be empty,
50 and for node and instance it must be a list of valid item
51 names (short names are valid as usual, e.g. node1 instead of
54 For _SHUTDOWN_CLUSTER, all instances will be returned. For
55 _SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as
56 primary/secondary will be shutdown. For _SHUTDOWN_NODES_BOTH, all
57 instances having those nodes as either primary or secondary will be
58 returned. For _SHUTDOWN_INSTANCES, the given instances will be
62 if mode == _SHUTDOWN_CLUSTER:
64 raise errors.OpPrereqError("Cluster filter mode takes no arguments")
65 op = opcodes.OpQueryInstances(output_fields=["name"], names=[])
66 idata = SubmitOpCode(op)
67 inames = [row[0] for row in idata]
69 elif mode in (_SHUTDOWN_NODES_BOTH,
73 raise errors.OpPrereqError("No node names passed")
74 op = opcodes.OpQueryNodes(output_fields=["name", "pinst_list",
75 "sinst_list"], names=names)
76 ndata = SubmitOpCode(op)
77 ipri = [row[1] for row in ndata]
78 pri_names = list(itertools.chain(*ipri))
79 isec = [row[2] for row in ndata]
80 sec_names = list(itertools.chain(*isec))
81 if mode == _SHUTDOWN_NODES_BOTH:
82 inames = pri_names + sec_names
83 elif mode == _SHUTDOWN_NODES_PRI:
85 elif mode == _SHUTDOWN_NODES_SEC:
88 raise errors.ProgrammerError("Unhandled shutdown type")
90 elif mode == _SHUTDOWN_INSTANCES:
92 raise errors.OpPrereqError("No instance names passed")
93 op = opcodes.OpQueryInstances(output_fields=["name"], names=names)
94 idata = SubmitOpCode(op)
95 inames = [row[0] for row in idata]
98 raise errors.OpPrereqError("Unknown mode '%s'" % mode)
103 def _ConfirmOperation(inames, text):
104 """Ask the user to confirm an operation on a list of instances.
106 This function is used to request confirmation for doing an operation
107 on a given list of instances.
109 The inames argument is what the selection algorithm computed, and
110 the text argument is the operation we should tell the user to
111 confirm (e.g. 'shutdown' or 'startup').
113 Returns: boolean depending on user's confirmation.
117 msg = ("The %s will operate on %d instances.\n"
118 "Do you want to continue?" % (text, count))
119 affected = ("\nAffected instances:\n" +
120 "\n".join([" %s" % name for name in inames]))
122 choices = [('y', True, 'Yes, execute the %s' % text),
123 ('n', False, 'No, abort the %s' % text)]
126 choices.insert(1, ('v', 'v', 'View the list of affected instances'))
131 choice = AskUser(ask, choices)
134 choice = AskUser(msg + affected, choices)
138 def _TransformPath(user_input):
139 """Transform a user path into a canonical value.
141 This function transforms the a path passed as textual information
142 into the constants that the LU code expects.
146 if user_input.lower() == "default":
147 result_path = constants.VALUE_DEFAULT
148 elif user_input.lower() == "none":
149 result_path = constants.VALUE_NONE
151 if not os.path.isabs(user_input):
152 raise errors.OpPrereqError("Path '%s' is not an absolute filename" %
154 result_path = user_input
156 result_path = constants.VALUE_DEFAULT
161 def ListInstances(opts, args):
162 """List instances and their properties.
165 if opts.output is None:
166 selected_fields = ["name", "os", "pnode", "status", "oper_ram"]
168 selected_fields = opts.output.split(",")
170 op = opcodes.OpQueryInstances(output_fields=selected_fields, names=[])
171 output = SubmitOpCode(op)
173 if not opts.no_headers:
175 "name": "Instance", "os": "OS", "pnode": "Primary_node",
176 "snodes": "Secondary_Nodes", "admin_state": "Autostart",
177 "oper_state": "Running", "admin_ram": "Configured_memory",
178 "oper_ram": "Memory", "disk_template": "Disk_template",
179 "ip": "IP Address", "mac": "MAC Address",
180 "bridge": "Bridge", "vcpus": "VCPUs",
181 "sda_size": "Disk/0", "sdb_size": "Disk/1",
187 if opts.human_readable:
188 unitfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
192 numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size", "vcpus"]
194 # change raw values to nicer strings
196 for idx, field in enumerate(selected_fields):
198 if field == "snodes":
199 val = ",".join(val) or "-"
200 elif field == "admin_state":
205 elif field == "oper_state":
212 elif field == "oper_ram":
215 elif field == "sda_size" or field == "sdb_size":
220 data = GenerateTable(separator=opts.separator, headers=headers,
221 fields=selected_fields, unitfields=unitfields,
222 numfields=numfields, data=output)
225 logger.ToStdout(line)
230 def AddInstance(opts, args):
231 """Add an instance to the cluster.
234 opts - class with options as members
235 args - list with a single element, the instance name
237 mem - amount of memory to allocate to instance (MiB)
238 size - amount of disk space to allocate to instance (MiB)
239 os - which OS to run on instance
240 node - node to run new instance on
245 (pnode, snode) = SplitNodeOption(opts.node)
247 kernel_path = _TransformPath(opts.kernel_path)
248 initrd_path = _TransformPath(opts.initrd_path)
250 op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
251 disk_size=opts.size, swap_size=opts.swap,
252 disk_template=opts.disk_template,
253 mode=constants.INSTANCE_CREATE,
254 os_type=opts.os, pnode=pnode,
255 snode=snode, vcpus=opts.vcpus,
256 ip=opts.ip, bridge=opts.bridge,
257 start=opts.start, ip_check=opts.ip_check,
258 wait_for_sync=opts.wait_for_sync,
260 kernel_path=kernel_path,
261 initrd_path=initrd_path,
262 hvm_boot_order=opts.hvm_boot_order,
263 file_storage_dir=opts.file_storage_dir,
264 file_driver=opts.file_driver,
265 iallocator=opts.iallocator)
270 def ReinstallInstance(opts, args):
271 """Reinstall an instance.
274 opts - class with options as members
275 args - list containing a single element, the instance name
278 instance_name = args[0]
281 usertext = ("This will reinstall the instance %s and remove"
282 " all data. Continue?") % instance_name
283 if not AskUser(usertext):
286 op = opcodes.OpReinstallInstance(instance_name=instance_name,
293 def RemoveInstance(opts, args):
294 """Remove an instance.
297 opts - class with options as members
298 args - list containing a single element, the instance name
301 instance_name = args[0]
305 usertext = ("This will remove the volumes of the instance %s"
306 " (including mirrors), thus removing all the data"
307 " of the instance. Continue?") % instance_name
308 if not AskUser(usertext):
311 op = opcodes.OpRemoveInstance(instance_name=instance_name,
312 ignore_failures=opts.ignore_failures)
317 def RenameInstance(opts, args):
318 """Rename an instance.
321 opts - class with options as members
322 args - list containing two elements, the instance name and the new name
325 op = opcodes.OpRenameInstance(instance_name=args[0],
327 ignore_ip=opts.ignore_ip)
333 def ActivateDisks(opts, args):
334 """Activate an instance's disks.
336 This serves two purposes:
337 - it allows one (as long as the instance is not running) to mount
338 the disks and modify them from the node
339 - it repairs inactive secondary drbds
342 instance_name = args[0]
343 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
344 disks_info = SubmitOpCode(op)
345 for host, iname, nname in disks_info:
346 print "%s:%s:%s" % (host, iname, nname)
350 def DeactivateDisks(opts, args):
351 """Command-line interface for _ShutdownInstanceBlockDevices.
353 This function takes the instance name, looks for its primary node
354 and the tries to shutdown its block devices on that node.
357 instance_name = args[0]
358 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
363 def StartupInstance(opts, args):
364 """Startup an instance.
367 opts - class with options as members
368 args - list containing a single element, the instance name
371 if opts.multi_mode is None:
372 opts.multi_mode = _SHUTDOWN_INSTANCES
373 inames = _ExpandMultiNames(opts.multi_mode, args)
375 raise errors.OpPrereqError("Selection filter does not match any instances")
376 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
377 if not (opts.force_multi or not multi_on
378 or _ConfirmOperation(inames, "startup")):
381 op = opcodes.OpStartupInstance(instance_name=name,
383 extra_args=opts.extra_args)
385 logger.ToStdout("Starting up %s" % name)
390 def RebootInstance(opts, args):
391 """Reboot an instance
394 opts - class with options as members
395 args - list containing a single element, the instance name
398 if opts.multi_mode is None:
399 opts.multi_mode = _SHUTDOWN_INSTANCES
400 inames = _ExpandMultiNames(opts.multi_mode, args)
402 raise errors.OpPrereqError("Selection filter does not match any instances")
403 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
404 if not (opts.force_multi or not multi_on
405 or _ConfirmOperation(inames, "reboot")):
408 op = opcodes.OpRebootInstance(instance_name=name,
409 reboot_type=opts.reboot_type,
410 ignore_secondaries=opts.ignore_secondaries)
416 def ShutdownInstance(opts, args):
417 """Shutdown an instance.
420 opts - class with options as members
421 args - list containing a single element, the instance name
424 if opts.multi_mode is None:
425 opts.multi_mode = _SHUTDOWN_INSTANCES
426 inames = _ExpandMultiNames(opts.multi_mode, args)
428 raise errors.OpPrereqError("Selection filter does not match any instances")
429 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
430 if not (opts.force_multi or not multi_on
431 or _ConfirmOperation(inames, "shutdown")):
434 op = opcodes.OpShutdownInstance(instance_name=name)
436 logger.ToStdout("Shutting down %s" % name)
441 def ReplaceDisks(opts, args):
442 """Replace the disks of an instance
445 opts - class with options as members
446 args - list with a single element, the instance name
449 instance_name = args[0]
450 new_2ndary = opts.new_secondary
451 iallocator = opts.iallocator
452 if opts.disks is None:
453 disks = ["sda", "sdb"]
455 disks = opts.disks.split(",")
456 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
457 mode = constants.REPLACE_DISK_ALL
458 elif opts.on_primary: # only on primary:
459 mode = constants.REPLACE_DISK_PRI
460 if new_2ndary is not None or iallocator is not None:
461 raise errors.OpPrereqError("Can't change secondary node on primary disk"
463 elif opts.on_secondary is not None or iallocator is not None:
465 mode = constants.REPLACE_DISK_SEC
467 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
468 remote_node=new_2ndary, mode=mode,
469 iallocator=iallocator)
474 def FailoverInstance(opts, args):
475 """Failover an instance.
477 The failover is done by shutting it down on its present node and
478 starting it on the secondary.
481 opts - class with options as members
482 args - list with a single element, the instance name
484 force - whether to failover without asking questions.
487 instance_name = args[0]
491 usertext = ("Failover will happen to image %s."
492 " This requires a shutdown of the instance. Continue?" %
494 if not AskUser(usertext):
497 op = opcodes.OpFailoverInstance(instance_name=instance_name,
498 ignore_consistency=opts.ignore_consistency)
503 def ConnectToInstanceConsole(opts, args):
504 """Connect to the console of an instance.
507 opts - class with options as members
508 args - list with a single element, the instance name
511 instance_name = args[0]
513 op = opcodes.OpConnectConsole(instance_name=instance_name)
514 cmd = SubmitOpCode(op)
516 if opts.show_command:
517 print utils.ShellQuoteArgs(cmd)
519 # drop lock and exec so other commands can run while we have console
522 os.execvp(cmd[0], cmd)
524 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
525 (cmd, " ".join(argv)))
529 def _FormatBlockDevInfo(buf, dev, indent_level):
530 """Show block device information.
532 This is only used by ShowInstanceConfig(), but it's too big to be
533 left for an inline definition.
536 def helper(buf, dtype, status):
537 """Format one line for physical device status."""
539 buf.write("not active\n")
541 (path, major, minor, syncp, estt, degr, ldisk) = status
545 major_string = str(major)
550 minor_string = str(minor)
552 buf.write("%s (%s:%s)" % (path, major_string, minor_string))
553 if dtype in (constants.LD_MD_R1, constants.LD_DRBD7, constants.LD_DRBD8):
554 if syncp is not None:
555 sync_text = "*RECOVERING* %5.2f%%," % syncp
557 sync_text += " ETA %ds" % estt
559 sync_text += " ETA unknown"
561 sync_text = "in sync"
563 degr_text = "*DEGRADED*"
567 ldisk_text = " *MISSING DISK*"
570 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
571 elif dtype == constants.LD_LV:
573 ldisk_text = " *FAILED* (failed drive?)"
576 buf.write(ldisk_text)
579 if dev["iv_name"] is not None:
580 data = " - %s, " % dev["iv_name"]
583 data += "type: %s" % dev["dev_type"]
584 if dev["logical_id"] is not None:
585 data += ", logical_id: %s" % (dev["logical_id"],)
586 elif dev["physical_id"] is not None:
587 data += ", physical_id: %s" % (dev["physical_id"],)
588 buf.write("%*s%s\n" % (2*indent_level, "", data))
589 buf.write("%*s primary: " % (2*indent_level, ""))
590 helper(buf, dev["dev_type"], dev["pstatus"])
593 buf.write("%*s secondary: " % (2*indent_level, ""))
594 helper(buf, dev["dev_type"], dev["sstatus"])
597 for child in dev["children"]:
598 _FormatBlockDevInfo(buf, child, indent_level+1)
601 def ShowInstanceConfig(opts, args):
602 """Compute instance run-time status.
606 op = opcodes.OpQueryInstanceData(instances=args)
607 result = SubmitOpCode(op)
610 logger.ToStdout("No instances.")
615 for instance_name in result:
616 instance = result[instance_name]
617 buf.write("Instance name: %s\n" % instance["name"])
618 buf.write("State: configured to be %s, actual state is %s\n" %
619 (instance["config_state"], instance["run_state"]))
620 buf.write(" Nodes:\n")
621 buf.write(" - primary: %s\n" % instance["pnode"])
622 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
623 buf.write(" Operating system: %s\n" % instance["os"])
624 buf.write(" Allocated network port: %s\n" % instance["network_port"])
625 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
626 kpath = "(default: %s)" % constants.XEN_KERNEL
628 kpath = instance["kernel_path"]
629 buf.write(" Kernel path: %s\n" % kpath)
630 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
631 initrd = "(default: %s)" % constants.XEN_INITRD
632 elif instance["initrd_path"] == constants.VALUE_NONE:
635 initrd = instance["initrd_path"]
636 buf.write(" initrd: %s\n" % initrd)
637 buf.write(" HVM boot order: %s\n" % instance["hvm_boot_order"])
638 buf.write(" Hardware:\n")
639 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
640 buf.write(" - memory: %dMiB\n" % instance["memory"])
641 buf.write(" - NICs: %s\n" %
642 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
644 for mac, ip, bridge in instance["nics"]]))
645 buf.write(" Block devices:\n")
647 for device in instance["disks"]:
648 _FormatBlockDevInfo(buf, device, 1)
650 logger.ToStdout(buf.getvalue().rstrip('\n'))
654 def SetInstanceParams(opts, args):
655 """Modifies an instance.
657 All parameters take effect only at the next restart of the instance.
660 opts - class with options as members
661 args - list with a single element, the instance name
663 memory - the new memory size
664 vcpus - the new number of cpus
665 mac - the new MAC address of the instance
668 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
669 opts.kernel_path or opts.initrd_path or opts.hvm_boot_order):
670 logger.ToStdout("Please give at least one of the parameters.")
673 kernel_path = _TransformPath(opts.kernel_path)
674 initrd_path = _TransformPath(opts.initrd_path)
675 if opts.hvm_boot_order == 'default':
676 hvm_boot_order = constants.VALUE_DEFAULT
678 hvm_boot_order = opts.hvm_boot_order
680 op = opcodes.OpSetInstanceParams(instance_name=args[0], mem=opts.mem,
681 vcpus=opts.vcpus, ip=opts.ip,
682 bridge=opts.bridge, mac=opts.mac,
683 kernel_path=opts.kernel_path,
684 initrd_path=opts.initrd_path,
685 hvm_boot_order=hvm_boot_order)
686 result = SubmitOpCode(op)
689 logger.ToStdout("Modified instance %s" % args[0])
690 for param, data in result:
691 logger.ToStdout(" - %-5s -> %s" % (param, data))
692 logger.ToStdout("Please don't forget that these parameters take effect"
693 " only at the next start of the instance.")
697 # options used in more than one cmd
698 node_opt = make_option("-n", "--node", dest="node", help="Target node",
701 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
704 # multi-instance selection options
705 m_force_multi = make_option("--force-multiple", dest="force_multi",
706 help="Do not ask for confirmation when more than"
707 " one instance is affected",
708 action="store_true", default=False)
710 m_pri_node_opt = make_option("--primary", dest="multi_mode",
711 help="Filter by nodes (primary only)",
712 const=_SHUTDOWN_NODES_PRI, action="store_const")
714 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
715 help="Filter by nodes (secondary only)",
716 const=_SHUTDOWN_NODES_SEC, action="store_const")
718 m_node_opt = make_option("--node", dest="multi_mode",
719 help="Filter by nodes (primary and secondary)",
720 const=_SHUTDOWN_NODES_BOTH, action="store_const")
722 m_clust_opt = make_option("--all", dest="multi_mode",
723 help="Select all instances in the cluster",
724 const=_SHUTDOWN_CLUSTER, action="store_const")
726 m_inst_opt = make_option("--instance", dest="multi_mode",
727 help="Filter by instance name [default]",
728 const=_SHUTDOWN_INSTANCES, action="store_const")
731 # this is defined separately due to readability only
734 make_option("-n", "--node", dest="node",
735 help="Target node and optional secondary node",
736 metavar="<pnode>[:<snode>]"),
737 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
739 default=20 * 1024, type="unit", metavar="<size>"),
740 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
742 default=4 * 1024, type="unit", metavar="<size>"),
744 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
745 default=128, type="unit", metavar="<mem>"),
746 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
747 default=1, type="int", metavar="<PROC>"),
748 make_option("-t", "--disk-template", dest="disk_template",
749 help="Custom disk setup (diskless, file, plain or drbd)",
750 default=None, metavar="TEMPL"),
751 make_option("-i", "--ip", dest="ip",
752 help="IP address ('none' [default], 'auto', or specify address)",
753 default='none', type="string", metavar="<ADDRESS>"),
754 make_option("--mac", dest="mac",
755 help="MAC address ('auto' [default], or specify address)",
756 default='auto', type="string", metavar="<MACADDRESS>"),
757 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
758 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
759 make_option("-b", "--bridge", dest="bridge",
760 help="Bridge to connect this instance to",
761 default=None, metavar="<bridge>"),
762 make_option("--no-start", dest="start", default=True,
763 action="store_false", help="Don't start the instance after"
765 make_option("--no-ip-check", dest="ip_check", default=True,
766 action="store_false", help="Don't check that the instance's IP"
767 " is alive (only valid with --no-start)"),
768 make_option("--kernel", dest="kernel_path",
769 help="Path to the instances' kernel (or 'default')",
771 type="string", metavar="<FILENAME>"),
772 make_option("--initrd", dest="initrd_path",
773 help="Path to the instances' initrd (or 'none', or 'default')",
775 type="string", metavar="<FILENAME>"),
776 make_option("--hvm-boot-order", dest="hvm_boot_order",
777 help="Boot device order for HVM (one or more of [acdn])",
778 default=None, type="string", metavar="<BOOTORDER>"),
779 make_option("--file-storage-dir", dest="file_storage_dir",
780 help="Relative path under default cluster-wide file storage dir"
781 " to store file-based disks", default=None,
783 make_option("--file-driver", dest="file_driver", help="Driver to use"
784 " for image files", default="loop", metavar="<DRIVER>"),
785 make_option("--iallocator", metavar="<NAME>",
786 help="Select nodes for the instance automatically using the"
787 " <NAME> iallocator plugin", default=None, type="string"),
791 'add': (AddInstance, ARGS_ONE, add_opts,
793 "Creates and adds a new instance to the cluster"),
794 'console': (ConnectToInstanceConsole, ARGS_ONE,
796 make_option("--show-cmd", dest="show_command",
797 action="store_true", default=False,
798 help=("Show command instead of executing it"))],
799 "[--show-cmd] <instance>",
800 "Opens a console on the specified instance"),
801 'failover': (FailoverInstance, ARGS_ONE,
802 [DEBUG_OPT, FORCE_OPT,
803 make_option("--ignore-consistency", dest="ignore_consistency",
804 action="store_true", default=False,
805 help="Ignore the consistency of the disks on"
809 "Stops the instance and starts it on the backup node, using"
810 " the remote mirror (only for instances of type drbd)"),
811 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
812 "Show information on the specified instance"),
813 'list': (ListInstances, ARGS_NONE,
814 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "",
815 "Lists the instances and their status. The available fields are"
816 " (see the man page for details): status, oper_state, oper_ram,"
817 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
818 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
819 " list is (in order): name, os, pnode, status,"
821 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
822 "[-f] <instance>", "Reinstall a stopped instance"),
823 'remove': (RemoveInstance, ARGS_ONE,
824 [DEBUG_OPT, FORCE_OPT,
825 make_option("--ignore-failures", dest="ignore_failures",
826 action="store_true", default=False,
827 help=("Remove the instance from the cluster even"
828 " if there are failures during the removal"
829 " process (shutdown, disk removal, etc.)")),
831 "[-f] <instance>", "Shuts down the instance and removes it"),
832 'rename': (RenameInstance, ARGS_FIXED(2),
834 make_option("--no-ip-check", dest="ignore_ip",
835 help="Do not check that the IP of the new name"
837 default=False, action="store_true"),
839 "<instance> <new_name>", "Rename the instance"),
840 'replace-disks': (ReplaceDisks, ARGS_ONE,
842 make_option("-n", "--new-secondary", dest="new_secondary",
843 help=("New secondary node (for secondary"
844 " node change)"), metavar="NODE"),
845 make_option("-p", "--on-primary", dest="on_primary",
846 default=False, action="store_true",
847 help=("Replace the disk(s) on the primary"
848 " node (only for the drbd template)")),
849 make_option("-s", "--on-secondary", dest="on_secondary",
850 default=False, action="store_true",
851 help=("Replace the disk(s) on the secondary"
852 " node (only for the drbd template)")),
853 make_option("--disks", dest="disks", default=None,
854 help=("Comma-separated list of disks"
855 " to replace (e.g. sda) (optional,"
856 " defaults to all disks")),
857 make_option("--iallocator", metavar="<NAME>",
858 help="Select new secondary for the instance"
859 " automatically using the"
860 " <NAME> iallocator plugin (enables"
861 " secondary node replacement)",
862 default=None, type="string"),
864 "[-s|-p|-n NODE] <instance>",
865 "Replaces all disks for the instance"),
866 'modify': (SetInstanceParams, ARGS_ONE,
867 [DEBUG_OPT, FORCE_OPT,
868 cli_option("-m", "--memory", dest="mem",
870 default=None, type="unit", metavar="<mem>"),
871 make_option("-p", "--cpu", dest="vcpus",
872 help="Number of virtual CPUs",
873 default=None, type="int", metavar="<PROC>"),
874 make_option("-i", "--ip", dest="ip",
875 help="IP address ('none' or numeric IP)",
876 default=None, type="string", metavar="<ADDRESS>"),
877 make_option("-b", "--bridge", dest="bridge",
878 help="Bridge to connect this instance to",
879 default=None, type="string", metavar="<bridge>"),
880 make_option("--mac", dest="mac",
881 help="MAC address", default=None,
882 type="string", metavar="<MACADDRESS>"),
883 make_option("--kernel", dest="kernel_path",
884 help="Path to the instances' kernel (or"
885 " 'default')", default=None,
886 type="string", metavar="<FILENAME>"),
887 make_option("--initrd", dest="initrd_path",
888 help="Path to the instances' initrd (or 'none', or"
889 " 'default')", default=None,
890 type="string", metavar="<FILENAME>"),
891 make_option("--hvm-boot-order", dest="hvm_boot_order",
892 help="boot device order for HVM"
893 "(either one or more of [acdn] or 'default')",
894 default=None, type="string", metavar="<BOOTORDER>"),
896 "<instance>", "Alters the parameters of an instance"),
897 'shutdown': (ShutdownInstance, ARGS_ANY,
898 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
899 m_clust_opt, m_inst_opt, m_force_multi],
900 "<instance>", "Stops an instance"),
901 'startup': (StartupInstance, ARGS_ANY,
902 [DEBUG_OPT, FORCE_OPT, m_force_multi,
903 make_option("-e", "--extra", dest="extra_args",
904 help="Extra arguments for the instance's kernel",
905 default=None, type="string", metavar="<PARAMS>"),
906 m_node_opt, m_pri_node_opt, m_sec_node_opt,
907 m_clust_opt, m_inst_opt,
909 "<instance>", "Starts an instance"),
911 'reboot': (RebootInstance, ARGS_ANY,
912 [DEBUG_OPT, m_force_multi,
913 make_option("-e", "--extra", dest="extra_args",
914 help="Extra arguments for the instance's kernel",
915 default=None, type="string", metavar="<PARAMS>"),
916 make_option("-t", "--type", dest="reboot_type",
917 help="Type of reboot: soft/hard/full",
918 default=constants.INSTANCE_REBOOT_SOFT,
919 type="string", metavar="<REBOOT>"),
920 make_option("--ignore-secondaries", dest="ignore_secondaries",
921 default=False, action="store_true",
922 help="Ignore errors from secondaries"),
923 m_node_opt, m_pri_node_opt, m_sec_node_opt,
924 m_clust_opt, m_inst_opt,
926 "<instance>", "Reboots an instance"),
927 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
929 "Activate an instance's disks"),
930 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
932 "Deactivate an instance's disks"),
933 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
934 "<node_name>", "List the tags of the given instance"),
935 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
936 "<node_name> tag...", "Add tags to the given instance"),
937 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
938 "<node_name> tag...", "Remove tags from given instance"),
942 'activate_block_devs': 'activate-disks',
943 'replace_disks': 'replace-disks',
948 if __name__ == '__main__':
949 sys.exit(GenericMain(commands, aliases=aliases,
950 override={"tag_type": constants.TAG_INSTANCE}))