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"
42 def _ExpandMultiNames(mode, names):
43 """Expand the given names using the passed mode.
46 - mode, which can be one of _SHUTDOWN_CLUSTER, _SHUTDOWN_NODES_BOTH,
47 _SHUTDOWN_NODES_PRI, _SHUTDOWN_NODES_SEC or _SHUTDOWN_INSTANCES
48 - names, which is a list of names; for cluster, it must be empty,
49 and for node and instance it must be a list of valid item
50 names (short names are valid as usual, e.g. node1 instead of
53 For _SHUTDOWN_CLUSTER, all instances will be returned. For
54 _SHUTDOWN_NODES_PRI/SEC, all instances having those nodes as
55 primary/secondary will be shutdown. For _SHUTDOWN_NODES_BOTH, all
56 instances having those nodes as either primary or secondary will be
57 returned. For _SHUTDOWN_INSTANCES, the given instances will be
61 if mode == _SHUTDOWN_CLUSTER:
63 raise errors.OpPrereqError("Cluster filter mode takes no arguments")
64 op = opcodes.OpQueryInstances(output_fields=["name"], names=[])
65 idata = SubmitOpCode(op)
66 inames = [row[0] for row in idata]
68 elif mode in (_SHUTDOWN_NODES_BOTH,
72 raise errors.OpPrereqError("No node names passed")
73 op = opcodes.OpQueryNodes(output_fields=["name", "pinst_list",
74 "sinst_list"], names=names)
75 ndata = SubmitOpCode(op)
76 ipri = [row[1] for row in ndata]
77 pri_names = list(itertools.chain(*ipri))
78 isec = [row[2] for row in ndata]
79 sec_names = list(itertools.chain(*isec))
80 if mode == _SHUTDOWN_NODES_BOTH:
81 inames = pri_names + sec_names
82 elif mode == _SHUTDOWN_NODES_PRI:
84 elif mode == _SHUTDOWN_NODES_SEC:
87 raise errors.ProgrammerError("Unhandled shutdown type")
89 elif mode == _SHUTDOWN_INSTANCES:
91 raise errors.OpPrereqError("No instance names passed")
92 op = opcodes.OpQueryInstances(output_fields=["name"], names=names)
93 idata = SubmitOpCode(op)
94 inames = [row[0] for row in idata]
97 raise errors.OpPrereqError("Unknown mode '%s'" % mode)
102 def _ConfirmOperation(inames, text):
103 """Ask the user to confirm an operation on a list of instances.
105 This function is used to request confirmation for doing an operation
106 on a given list of instances.
108 The inames argument is what the selection algorithm computed, and
109 the text argument is the operation we should tell the user to
110 confirm (e.g. 'shutdown' or 'startup').
112 Returns: boolean depending on user's confirmation.
116 msg = ("The %s will operate on %d instances.\n"
117 "Do you want to continue?" % (text, count))
118 affected = ("\nAffected instances:\n" +
119 "\n".join([" %s" % name for name in inames]))
121 choices = [('y', True, 'Yes, execute the %s' % text),
122 ('n', False, 'No, abort the %s' % text)]
125 choices.insert(1, ('v', 'v', 'View the list of affected instances'))
130 choice = AskUser(ask, choices)
133 choice = AskUser(choices, msg + affected)
137 def _TransformPath(user_input):
138 """Transform a user path into a canonical value.
140 This function transforms the a path passed as textual information
141 into the constants that the LU code expects.
145 if user_input.lower() == "default":
146 result_path = constants.VALUE_DEFAULT
147 elif user_input.lower() == "none":
148 result_path = constants.VALUE_NONE
150 if not os.path.isabs(user_input):
151 raise errors.OpPrereqError("Path '%s' is not an absolute filename" %
153 result_path = user_input
155 result_path = constants.VALUE_DEFAULT
160 def ListInstances(opts, args):
161 """List instances and their properties.
164 if opts.output is None:
165 selected_fields = ["name", "os", "pnode", "admin_state",
166 "oper_state", "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:
174 headers = {"name": "Instance", "os": "OS", "pnode": "Primary_node",
175 "snodes": "Secondary_Nodes", "admin_state": "Autostart",
176 "oper_state": "Status", "admin_ram": "Configured_memory",
177 "oper_ram": "Memory", "disk_template": "Disk_template",
178 "ip": "IP Address", "mac": "MAC Address",
179 "bridge": "Bridge", "vcpus": "VCPUs",
180 "sda_size": "Disk/0", "sdb_size": "Disk/1"}
184 if opts.human_readable:
185 unitfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
189 numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size", "vcpus"]
191 # change raw values to nicer strings
193 for idx, field in enumerate(selected_fields):
195 if field == "snodes":
196 val = ",".join(val) or "-"
197 elif field == "admin_state":
202 elif field == "oper_state":
209 elif field == "oper_ram":
212 elif field == "sda_size" or field == "sdb_size":
217 data = GenerateTable(separator=opts.separator, headers=headers,
218 fields=selected_fields, unitfields=unitfields,
219 numfields=numfields, data=output)
222 logger.ToStdout(line)
227 def AddInstance(opts, args):
228 """Add an instance to the cluster.
231 opts - class with options as members
232 args - list with a single element, the instance name
234 mem - amount of memory to allocate to instance (MiB)
235 size - amount of disk space to allocate to instance (MiB)
236 os - which OS to run on instance
237 node - node to run new instance on
242 (pnode, snode) = SplitNodeOption(opts.node)
244 kernel_path = _TransformPath(opts.kernel_path)
245 initrd_path = _TransformPath(opts.initrd_path)
247 op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
248 disk_size=opts.size, swap_size=opts.swap,
249 disk_template=opts.disk_template,
250 mode=constants.INSTANCE_CREATE,
251 os_type=opts.os, pnode=pnode,
252 snode=snode, vcpus=opts.vcpus,
253 ip=opts.ip, bridge=opts.bridge,
254 start=opts.start, ip_check=opts.ip_check,
255 wait_for_sync=opts.wait_for_sync,
257 kernel_path=kernel_path,
258 initrd_path=initrd_path,
259 hvm_boot_order=opts.hvm_boot_order)
264 def ReinstallInstance(opts, args):
265 """Reinstall an instance.
268 opts - class with options as members
269 args - list containing a single element, the instance name
272 instance_name = args[0]
275 usertext = ("This will reinstall the instance %s and remove"
276 " all data. Continue?") % instance_name
277 if not AskUser(usertext):
280 op = opcodes.OpReinstallInstance(instance_name=instance_name,
287 def RemoveInstance(opts, args):
288 """Remove an instance.
291 opts - class with options as members
292 args - list containing a single element, the instance name
295 instance_name = args[0]
299 usertext = ("This will remove the volumes of the instance %s"
300 " (including mirrors), thus removing all the data"
301 " of the instance. Continue?") % instance_name
302 if not AskUser(usertext):
305 op = opcodes.OpRemoveInstance(instance_name=instance_name,
306 ignore_failures=opts.ignore_failures)
311 def RenameInstance(opts, args):
312 """Rename an instance.
315 opts - class with options as members
316 args - list containing two elements, the instance name and the new name
319 op = opcodes.OpRenameInstance(instance_name=args[0],
321 ignore_ip=opts.ignore_ip)
327 def ActivateDisks(opts, args):
328 """Activate an instance's disks.
330 This serves two purposes:
331 - it allows one (as long as the instance is not running) to mount
332 the disks and modify them from the node
333 - it repairs inactive secondary drbds
336 instance_name = args[0]
337 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
338 disks_info = SubmitOpCode(op)
339 for host, iname, nname in disks_info:
340 print "%s:%s:%s" % (host, iname, nname)
344 def DeactivateDisks(opts, args):
345 """Command-line interface for _ShutdownInstanceBlockDevices.
347 This function takes the instance name, looks for its primary node
348 and the tries to shutdown its block devices on that node.
351 instance_name = args[0]
352 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
357 def StartupInstance(opts, args):
358 """Startup an instance.
361 opts - class with options as members
362 args - list containing a single element, the instance name
365 if opts.multi_mode is None:
366 opts.multi_mode = _SHUTDOWN_INSTANCES
367 inames = _ExpandMultiNames(opts.multi_mode, args)
369 raise errors.OpPrereqError("Selection filter does not match any instances")
370 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
371 if not (opts.force_multi or not multi_on
372 or _ConfirmOperation(inames, "startup")):
375 op = opcodes.OpStartupInstance(instance_name=name,
377 extra_args=opts.extra_args)
379 logger.ToStdout("Starting up %s" % name)
383 def RebootInstance(opts, args):
384 """Reboot an instance
387 opts - class with options as members
388 args - list containing a single element, the instance name
391 if opts.multi_mode is None:
392 opts.multi_mode = _SHUTDOWN_INSTANCES
393 inames = _ExpandMultiNames(opts.multi_mode, args)
395 raise errors.OpPrereqError("Selection filter does not match any instances")
396 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
397 if not (opts.force_multi or not multi_on
398 or _ConfirmOperation(inames, "reboot")):
401 op = opcodes.OpRebootInstance(instance_name=name,
402 reboot_type=opts.reboot_type,
403 ignore_secondaries=opts.ignore_secondaries)
408 def ShutdownInstance(opts, args):
409 """Shutdown an instance.
412 opts - class with options as members
413 args - list containing a single element, the instance name
416 if opts.multi_mode is None:
417 opts.multi_mode = _SHUTDOWN_INSTANCES
418 inames = _ExpandMultiNames(opts.multi_mode, args)
420 raise errors.OpPrereqError("Selection filter does not match any instances")
421 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
422 if not (opts.force_multi or not multi_on
423 or _ConfirmOperation(inames, "shutdown")):
426 op = opcodes.OpShutdownInstance(instance_name=name)
428 logger.ToStdout("Shutting down %s" % name)
433 def AddMDDRBDComponent(opts, args):
434 """Add a new component to a remote_raid1 disk.
437 opts - class with options as members
438 args - list with a single element, the instance name
441 op = opcodes.OpAddMDDRBDComponent(instance_name=args[0],
443 remote_node=opts.node)
448 def RemoveMDDRBDComponent(opts, args):
449 """Remove a component from a remote_raid1 disk.
452 opts - class with options as members
453 args - list with a single element, the instance name
456 op = opcodes.OpRemoveMDDRBDComponent(instance_name=args[0],
463 def ReplaceDisks(opts, args):
464 """Replace the disks of an instance
467 opts - class with options as members
468 args - list with a single element, the instance name
471 instance_name = args[0]
472 new_2ndary = opts.new_secondary
473 if opts.disks is None:
474 disks = ["sda", "sdb"]
476 disks = opts.disks.split(",")
477 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
478 mode = constants.REPLACE_DISK_ALL
479 elif opts.on_primary: # only on primary:
480 mode = constants.REPLACE_DISK_PRI
481 if new_2ndary is not None:
482 raise errors.OpPrereqError("Can't change secondary node on primary disk"
484 elif opts.on_secondary is not None: # only on secondary
485 mode = constants.REPLACE_DISK_SEC
487 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
488 remote_node=new_2ndary, mode=mode)
493 def FailoverInstance(opts, args):
494 """Failover an instance.
496 The failover is done by shutting it down on its present node and
497 starting it on the secondary.
500 opts - class with options as members
501 args - list with a single element, the instance name
503 force - whether to failover without asking questions.
506 instance_name = args[0]
510 usertext = ("Failover will happen to image %s."
511 " This requires a shutdown of the instance. Continue?" %
513 if not AskUser(usertext):
516 op = opcodes.OpFailoverInstance(instance_name=instance_name,
517 ignore_consistency=opts.ignore_consistency)
522 def ConnectToInstanceConsole(opts, args):
523 """Connect to the console of an instance.
526 opts - class with options as members
527 args - list with a single element, the instance name
530 instance_name = args[0]
532 op = opcodes.OpConnectConsole(instance_name=instance_name)
533 cmd, argv = SubmitOpCode(op)
534 # drop lock and exec so other commands can run while we have console
539 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
540 (cmd, " ".join(argv)))
544 def _FormatBlockDevInfo(buf, dev, indent_level):
545 """Show block device information.
547 This is only used by ShowInstanceConfig(), but it's too big to be
548 left for an inline definition.
551 def helper(buf, dtype, status):
552 """Format one line for phsyical device status."""
554 buf.write("not active\n")
556 (path, major, minor, syncp, estt, degr, ldisk) = status
557 buf.write("%s (%d:%d)" % (path, major, minor))
558 if dtype in (constants.LD_MD_R1, constants.LD_DRBD7, constants.LD_DRBD8):
559 if syncp is not None:
560 sync_text = "*RECOVERING* %5.2f%%," % syncp
562 sync_text += " ETA %ds" % estt
564 sync_text += " ETA unknown"
566 sync_text = "in sync"
568 degr_text = "*DEGRADED*"
572 ldisk_text = " *MISSING DISK*"
575 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
576 elif dtype == constants.LD_LV:
578 ldisk_text = " *FAILED* (failed drive?)"
581 buf.write(ldisk_text)
584 if dev["iv_name"] is not None:
585 data = " - %s, " % dev["iv_name"]
588 data += "type: %s" % dev["dev_type"]
589 if dev["logical_id"] is not None:
590 data += ", logical_id: %s" % (dev["logical_id"],)
591 elif dev["physical_id"] is not None:
592 data += ", physical_id: %s" % (dev["physical_id"],)
593 buf.write("%*s%s\n" % (2*indent_level, "", data))
594 buf.write("%*s primary: " % (2*indent_level, ""))
595 helper(buf, dev["dev_type"], dev["pstatus"])
598 buf.write("%*s secondary: " % (2*indent_level, ""))
599 helper(buf, dev["dev_type"], dev["sstatus"])
602 for child in dev["children"]:
603 _FormatBlockDevInfo(buf, child, indent_level+1)
606 def ShowInstanceConfig(opts, args):
607 """Compute instance run-time status.
611 op = opcodes.OpQueryInstanceData(instances=args)
612 result = SubmitOpCode(op)
615 logger.ToStdout("No instances.")
620 for instance_name in result:
621 instance = result[instance_name]
622 buf.write("Instance name: %s\n" % instance["name"])
623 buf.write("State: configured to be %s, actual state is %s\n" %
624 (instance["config_state"], instance["run_state"]))
625 buf.write(" Nodes:\n")
626 buf.write(" - primary: %s\n" % instance["pnode"])
627 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
628 buf.write(" Operating system: %s\n" % instance["os"])
629 buf.write(" Allocated network port: %s\n" % instance["network_port"])
630 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
631 kpath = "(default: %s)" % constants.XEN_KERNEL
633 kpath = instance["kernel_path"]
634 buf.write(" Kernel path: %s\n" % kpath)
635 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
636 initrd = "(default: %s)" % constants.XEN_INITRD
637 elif instance["initrd_path"] == constants.VALUE_NONE:
640 initrd = instance["initrd_path"]
641 buf.write(" initrd: %s\n" % initrd)
642 buf.write(" HVM boot order: %s\n" % instance["hvm_boot_order"])
643 buf.write(" Hardware:\n")
644 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
645 buf.write(" - memory: %dMiB\n" % instance["memory"])
646 buf.write(" - NICs: %s\n" %
647 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
649 for mac, ip, bridge in instance["nics"]]))
650 buf.write(" Block devices:\n")
652 for device in instance["disks"]:
653 _FormatBlockDevInfo(buf, device, 1)
655 logger.ToStdout(buf.getvalue().rstrip('\n'))
659 def SetInstanceParms(opts, args):
660 """Modifies an instance.
662 All parameters take effect only at the next restart of the instance.
665 opts - class with options as members
666 args - list with a single element, the instance name
668 memory - the new memory size
669 vcpus - the new number of cpus
670 mac - the new MAC address of the instance
673 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
674 opts.kernel_path or opts.initrd_path or opts.hvm_boot_order):
675 logger.ToStdout("Please give at least one of the parameters.")
678 kernel_path = _TransformPath(opts.kernel_path)
679 initrd_path = _TransformPath(opts.initrd_path)
680 if opts.hvm_boot_order == 'default':
681 hvm_boot_order = constants.VALUE_DEFAULT
683 hvm_boot_order = opts.hvm_boot_order
685 op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
686 vcpus=opts.vcpus, ip=opts.ip,
687 bridge=opts.bridge, mac=opts.mac,
688 kernel_path=opts.kernel_path,
689 initrd_path=opts.initrd_path,
690 hvm_boot_order=hvm_boot_order)
691 result = SubmitOpCode(op)
694 logger.ToStdout("Modified instance %s" % args[0])
695 for param, data in result:
696 logger.ToStdout(" - %-5s -> %s" % (param, data))
697 logger.ToStdout("Please don't forget that these parameters take effect"
698 " only at the next start of the instance.")
702 # options used in more than one cmd
703 node_opt = make_option("-n", "--node", dest="node", help="Target node",
706 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
709 # multi-instance selection options
710 m_force_multi = make_option("--force-multiple", dest="force_multi",
711 help="Do not ask for confirmation when more than"
712 " one instance is affected",
713 action="store_true", default=False)
715 m_pri_node_opt = make_option("--primary", dest="multi_mode",
716 help="Filter by nodes (primary only)",
717 const=_SHUTDOWN_NODES_PRI, action="store_const")
719 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
720 help="Filter by nodes (secondary only)",
721 const=_SHUTDOWN_NODES_SEC, action="store_const")
723 m_node_opt = make_option("--node", dest="multi_mode",
724 help="Filter by nodes (primary and secondary)",
725 const=_SHUTDOWN_NODES_BOTH, action="store_const")
727 m_clust_opt = make_option("--all", dest="multi_mode",
728 help="Select all instances in the cluster",
729 const=_SHUTDOWN_CLUSTER, action="store_const")
731 m_inst_opt = make_option("--instance", dest="multi_mode",
732 help="Filter by instance name [default]",
733 const=_SHUTDOWN_INSTANCES, action="store_const")
736 # this is defined separately due to readability only
739 make_option("-n", "--node", dest="node",
740 help="Target node and optional secondary node",
741 metavar="<pnode>[:<snode>]"),
742 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
744 default=20 * 1024, type="unit", metavar="<size>"),
745 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
747 default=4 * 1024, type="unit", metavar="<size>"),
749 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
750 default=128, type="unit", metavar="<mem>"),
751 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
752 default=1, type="int", metavar="<PROC>"),
753 make_option("-t", "--disk-template", dest="disk_template",
754 help="Custom disk setup (diskless, plain, local_raid1,"
755 " remote_raid1 or drbd)", default=None, metavar="TEMPL"),
756 make_option("-i", "--ip", dest="ip",
757 help="IP address ('none' [default], 'auto', or specify address)",
758 default='none', type="string", metavar="<ADDRESS>"),
759 make_option("--mac", dest="mac",
760 help="MAC address ('auto' [default], or specify address)",
761 default='auto', type="string", metavar="<MACADDRESS>"),
762 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
763 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
764 make_option("-b", "--bridge", dest="bridge",
765 help="Bridge to connect this instance to",
766 default=None, metavar="<bridge>"),
767 make_option("--no-start", dest="start", default=True,
768 action="store_false", help="Don't start the instance after"
770 make_option("--no-ip-check", dest="ip_check", default=True,
771 action="store_false", help="Don't check that the instance's IP"
772 " is alive (only valid with --no-start)"),
773 make_option("--kernel", dest="kernel_path",
774 help="Path to the instances' kernel (or 'default')",
776 type="string", metavar="<FILENAME>"),
777 make_option("--initrd", dest="initrd_path",
778 help="Path to the instances' initrd (or 'none', or 'default')",
780 type="string", metavar="<FILENAME>"),
781 make_option("--hvm-boot-order", dest="hvm_boot_order",
782 help="boot device order for HVM (one or more of [acdn])",
783 default=None, type="string", metavar="<BOOTORDER>"),
787 'add': (AddInstance, ARGS_ONE, add_opts,
789 "Creates and adds a new instance to the cluster"),
790 'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
791 [DEBUG_OPT, node_opt,
792 make_option("-b", "--disk", dest="disk", metavar="sdX",
793 help=("The name of the instance disk for which to"
794 " add the mirror"))],
795 "-n node -b disk <instance>",
796 "Creates a new mirror for the instance"),
797 'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT],
799 "Opens a console on the specified instance"),
800 'failover': (FailoverInstance, ARGS_ONE,
801 [DEBUG_OPT, FORCE_OPT,
802 make_option("--ignore-consistency", dest="ignore_consistency",
803 action="store_true", default=False,
804 help="Ignore the consistency of the disks on"
808 "Stops the instance and starts it on the backup node, using"
809 " the remote mirror (only for instances of type remote_raid1)"),
810 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
811 "Show information on the specified instance"),
812 'list': (ListInstances, ARGS_NONE,
813 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
814 "", "Lists the instances and their status. The available fields"
815 " are (see the man page for details): oper_state, oper_ram,"
816 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
817 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
818 " list is (in order): name, os, pnode, admin_state, oper_state,"
820 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
821 "[-f] <instance>", "Reinstall the instance"),
822 'remove': (RemoveInstance, ARGS_ONE,
823 [DEBUG_OPT, FORCE_OPT,
824 make_option("--ignore-failures", dest="ignore_failures",
825 action="store_true", default=False,
826 help=("Remove the instance from the cluster even"
827 " if there are failures during the removal"
828 " process (shutdown, disk removal, etc.)")),
830 "[-f] <instance>", "Shuts down the instance and removes it"),
831 'remove-mirror': (RemoveMDDRBDComponent, ARGS_ONE,
832 [DEBUG_OPT, node_opt,
833 make_option("-b", "--disk", dest="disk", metavar="sdX",
834 help=("The name of the instance disk"
835 " for which to add the mirror")),
836 make_option("-p", "--port", dest="port", metavar="PORT",
837 help=("The port of the drbd device"
838 " which to remove from the mirror"),
841 "-b disk -p port <instance>",
842 "Removes a mirror from the instance"),
843 'rename': (RenameInstance, ARGS_FIXED(2),
845 make_option("--no-ip-check", dest="ignore_ip",
846 help="Do not check that the IP of the new name"
848 default=False, action="store_true"),
850 "<instance> <new_name>", "Rename the instance"),
851 'replace-disks': (ReplaceDisks, ARGS_ONE,
853 make_option("-n", "--new-secondary", dest="new_secondary",
854 help=("New secondary node (for secondary"
855 " node change)"), metavar="NODE"),
856 make_option("-p", "--on-primary", dest="on_primary",
857 default=False, action="store_true",
858 help=("Replace the disk(s) on the primary"
859 " node (only for the drbd template)")),
860 make_option("-s", "--on-secondary", dest="on_secondary",
861 default=False, action="store_true",
862 help=("Replace the disk(s) on the secondary"
863 " node (only for the drbd template)")),
864 make_option("--disks", dest="disks", default=None,
865 help=("Comma-separated list of disks"
866 " to replace (e.g. sda) (optional,"
867 " defaults to all disks")),
869 "[-n NODE] <instance>",
870 "Replaces all disks for the instance"),
871 'modify': (SetInstanceParms, ARGS_ONE,
872 [DEBUG_OPT, FORCE_OPT,
873 cli_option("-m", "--memory", dest="mem",
875 default=None, type="unit", metavar="<mem>"),
876 make_option("-p", "--cpu", dest="vcpus",
877 help="Number of virtual CPUs",
878 default=None, type="int", metavar="<PROC>"),
879 make_option("-i", "--ip", dest="ip",
880 help="IP address ('none' or numeric IP)",
881 default=None, type="string", metavar="<ADDRESS>"),
882 make_option("-b", "--bridge", dest="bridge",
883 help="Bridge to connect this instance to",
884 default=None, type="string", metavar="<bridge>"),
885 make_option("--mac", dest="mac",
886 help="MAC address", default=None,
887 type="string", metavar="<MACADDRESS>"),
888 make_option("--kernel", dest="kernel_path",
889 help="Path to the instances' kernel (or"
890 " 'default')", default=None,
891 type="string", metavar="<FILENAME>"),
892 make_option("--initrd", dest="initrd_path",
893 help="Path to the instances' initrd (or 'none', or"
894 " 'default')", default=None,
895 type="string", metavar="<FILENAME>"),
896 make_option("--hvm-boot-order", dest="hvm_boot_order",
897 help="boot device order for HVM"
898 "(either one or more of [acdn] or 'default')",
899 default=None, type="string", metavar="<BOOTORDER>"),
901 "<instance>", "Alters the parameters of an instance"),
902 'shutdown': (ShutdownInstance, ARGS_ANY,
903 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
904 m_clust_opt, m_inst_opt, m_force_multi],
905 "<instance>", "Stops an instance"),
906 'startup': (StartupInstance, ARGS_ANY,
907 [DEBUG_OPT, FORCE_OPT, m_force_multi,
908 make_option("-e", "--extra", dest="extra_args",
909 help="Extra arguments for the instance's kernel",
910 default=None, type="string", metavar="<PARAMS>"),
911 m_node_opt, m_pri_node_opt, m_sec_node_opt,
912 m_clust_opt, m_inst_opt,
914 "<instance>", "Starts an instance"),
916 'reboot': (RebootInstance, ARGS_ANY,
917 [DEBUG_OPT, m_force_multi,
918 make_option("-e", "--extra", dest="extra_args",
919 help="Extra arguments for the instance's kernel",
920 default=None, type="string", metavar="<PARAMS>"),
921 make_option("-t", "--type", dest="reboot_type",
922 help="Type of reboot: soft/hard/full",
923 default=constants.INSTANCE_REBOOT_SOFT,
924 type="string", metavar="<REBOOT>"),
925 make_option("--ignore-secondaries", dest="ignore_secondaries",
926 default=False, action="store_true",
927 help="Ignore errors from secondaries"),
928 m_node_opt, m_pri_node_opt, m_sec_node_opt,
929 m_clust_opt, m_inst_opt,
931 "<instance>", "Reboots an instance"),
932 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
934 "Activate an instance's disks"),
935 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
937 "Deactivate an instance's disks"),
938 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
939 "<node_name>", "List the tags of the given instance"),
940 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
941 "<node_name> tag...", "Add tags to the given instance"),
942 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
943 "<node_name> tag...", "Remove tags from given instance"),
947 'activate_block_devs': 'activate-disks',
952 if __name__ == '__main__':
953 sys.exit(GenericMain(commands, aliases=aliases,
954 override={"tag_type": constants.TAG_INSTANCE}))