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(choices, msg + affected)
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)
267 def ReinstallInstance(opts, args):
268 """Reinstall an instance.
271 opts - class with options as members
272 args - list containing a single element, the instance name
275 instance_name = args[0]
278 usertext = ("This will reinstall the instance %s and remove"
279 " all data. Continue?") % instance_name
280 if not AskUser(usertext):
283 op = opcodes.OpReinstallInstance(instance_name=instance_name,
290 def RemoveInstance(opts, args):
291 """Remove an instance.
294 opts - class with options as members
295 args - list containing a single element, the instance name
298 instance_name = args[0]
302 usertext = ("This will remove the volumes of the instance %s"
303 " (including mirrors), thus removing all the data"
304 " of the instance. Continue?") % instance_name
305 if not AskUser(usertext):
308 op = opcodes.OpRemoveInstance(instance_name=instance_name,
309 ignore_failures=opts.ignore_failures)
314 def RenameInstance(opts, args):
315 """Rename an instance.
318 opts - class with options as members
319 args - list containing two elements, the instance name and the new name
322 op = opcodes.OpRenameInstance(instance_name=args[0],
324 ignore_ip=opts.ignore_ip)
330 def ActivateDisks(opts, args):
331 """Activate an instance's disks.
333 This serves two purposes:
334 - it allows one (as long as the instance is not running) to mount
335 the disks and modify them from the node
336 - it repairs inactive secondary drbds
339 instance_name = args[0]
340 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
341 disks_info = SubmitOpCode(op)
342 for host, iname, nname in disks_info:
343 print "%s:%s:%s" % (host, iname, nname)
347 def DeactivateDisks(opts, args):
348 """Command-line interface for _ShutdownInstanceBlockDevices.
350 This function takes the instance name, looks for its primary node
351 and the tries to shutdown its block devices on that node.
354 instance_name = args[0]
355 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
360 def StartupInstance(opts, args):
361 """Startup an instance.
364 opts - class with options as members
365 args - list containing a single element, the instance name
368 if opts.multi_mode is None:
369 opts.multi_mode = _SHUTDOWN_INSTANCES
370 inames = _ExpandMultiNames(opts.multi_mode, args)
372 raise errors.OpPrereqError("Selection filter does not match any instances")
373 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
374 if not (opts.force_multi or not multi_on
375 or _ConfirmOperation(inames, "startup")):
378 op = opcodes.OpStartupInstance(instance_name=name,
380 extra_args=opts.extra_args)
382 logger.ToStdout("Starting up %s" % name)
387 def RebootInstance(opts, args):
388 """Reboot an instance
391 opts - class with options as members
392 args - list containing a single element, the instance name
395 if opts.multi_mode is None:
396 opts.multi_mode = _SHUTDOWN_INSTANCES
397 inames = _ExpandMultiNames(opts.multi_mode, args)
399 raise errors.OpPrereqError("Selection filter does not match any instances")
400 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
401 if not (opts.force_multi or not multi_on
402 or _ConfirmOperation(inames, "reboot")):
405 op = opcodes.OpRebootInstance(instance_name=name,
406 reboot_type=opts.reboot_type,
407 ignore_secondaries=opts.ignore_secondaries)
413 def ShutdownInstance(opts, args):
414 """Shutdown an instance.
417 opts - class with options as members
418 args - list containing a single element, the instance name
421 if opts.multi_mode is None:
422 opts.multi_mode = _SHUTDOWN_INSTANCES
423 inames = _ExpandMultiNames(opts.multi_mode, args)
425 raise errors.OpPrereqError("Selection filter does not match any instances")
426 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
427 if not (opts.force_multi or not multi_on
428 or _ConfirmOperation(inames, "shutdown")):
431 op = opcodes.OpShutdownInstance(instance_name=name)
433 logger.ToStdout("Shutting down %s" % name)
438 def AddMDDRBDComponent(opts, args):
439 """Add a new component to a remote_raid1 disk.
442 opts - class with options as members
443 args - list with a single element, the instance name
446 op = opcodes.OpAddMDDRBDComponent(instance_name=args[0],
448 remote_node=opts.node)
453 def RemoveMDDRBDComponent(opts, args):
454 """Remove a component from a remote_raid1 disk.
457 opts - class with options as members
458 args - list with a single element, the instance name
461 op = opcodes.OpRemoveMDDRBDComponent(instance_name=args[0],
468 def ReplaceDisks(opts, args):
469 """Replace the disks of an instance
472 opts - class with options as members
473 args - list with a single element, the instance name
476 instance_name = args[0]
477 new_2ndary = opts.new_secondary
478 if opts.disks is None:
479 disks = ["sda", "sdb"]
481 disks = opts.disks.split(",")
482 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
483 mode = constants.REPLACE_DISK_ALL
484 elif opts.on_primary: # only on primary:
485 mode = constants.REPLACE_DISK_PRI
486 if new_2ndary is not None:
487 raise errors.OpPrereqError("Can't change secondary node on primary disk"
489 elif opts.on_secondary is not None: # only on secondary
490 mode = constants.REPLACE_DISK_SEC
492 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
493 remote_node=new_2ndary, mode=mode)
498 def FailoverInstance(opts, args):
499 """Failover an instance.
501 The failover is done by shutting it down on its present node and
502 starting it on the secondary.
505 opts - class with options as members
506 args - list with a single element, the instance name
508 force - whether to failover without asking questions.
511 instance_name = args[0]
515 usertext = ("Failover will happen to image %s."
516 " This requires a shutdown of the instance. Continue?" %
518 if not AskUser(usertext):
521 op = opcodes.OpFailoverInstance(instance_name=instance_name,
522 ignore_consistency=opts.ignore_consistency)
527 def ConnectToInstanceConsole(opts, args):
528 """Connect to the console of an instance.
531 opts - class with options as members
532 args - list with a single element, the instance name
535 instance_name = args[0]
537 op = opcodes.OpConnectConsole(instance_name=instance_name)
538 cmd, argv = SubmitOpCode(op)
539 # drop lock and exec so other commands can run while we have console
544 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
545 (cmd, " ".join(argv)))
549 def _FormatBlockDevInfo(buf, dev, indent_level):
550 """Show block device information.
552 This is only used by ShowInstanceConfig(), but it's too big to be
553 left for an inline definition.
556 def helper(buf, dtype, status):
557 """Format one line for physical device status."""
559 buf.write("not active\n")
561 (path, major, minor, syncp, estt, degr, ldisk) = status
562 buf.write("%s (%d:%d)" % (path, major, minor))
563 if dtype in (constants.LD_MD_R1, constants.LD_DRBD7, constants.LD_DRBD8):
564 if syncp is not None:
565 sync_text = "*RECOVERING* %5.2f%%," % syncp
567 sync_text += " ETA %ds" % estt
569 sync_text += " ETA unknown"
571 sync_text = "in sync"
573 degr_text = "*DEGRADED*"
577 ldisk_text = " *MISSING DISK*"
580 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
581 elif dtype == constants.LD_LV:
583 ldisk_text = " *FAILED* (failed drive?)"
586 buf.write(ldisk_text)
589 if dev["iv_name"] is not None:
590 data = " - %s, " % dev["iv_name"]
593 data += "type: %s" % dev["dev_type"]
594 if dev["logical_id"] is not None:
595 data += ", logical_id: %s" % (dev["logical_id"],)
596 elif dev["physical_id"] is not None:
597 data += ", physical_id: %s" % (dev["physical_id"],)
598 buf.write("%*s%s\n" % (2*indent_level, "", data))
599 buf.write("%*s primary: " % (2*indent_level, ""))
600 helper(buf, dev["dev_type"], dev["pstatus"])
603 buf.write("%*s secondary: " % (2*indent_level, ""))
604 helper(buf, dev["dev_type"], dev["sstatus"])
607 for child in dev["children"]:
608 _FormatBlockDevInfo(buf, child, indent_level+1)
611 def ShowInstanceConfig(opts, args):
612 """Compute instance run-time status.
616 op = opcodes.OpQueryInstanceData(instances=args)
617 result = SubmitOpCode(op)
620 logger.ToStdout("No instances.")
625 for instance_name in result:
626 instance = result[instance_name]
627 buf.write("Instance name: %s\n" % instance["name"])
628 buf.write("State: configured to be %s, actual state is %s\n" %
629 (instance["config_state"], instance["run_state"]))
630 buf.write(" Nodes:\n")
631 buf.write(" - primary: %s\n" % instance["pnode"])
632 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
633 buf.write(" Operating system: %s\n" % instance["os"])
634 buf.write(" Allocated network port: %s\n" % instance["network_port"])
635 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
636 kpath = "(default: %s)" % constants.XEN_KERNEL
638 kpath = instance["kernel_path"]
639 buf.write(" Kernel path: %s\n" % kpath)
640 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
641 initrd = "(default: %s)" % constants.XEN_INITRD
642 elif instance["initrd_path"] == constants.VALUE_NONE:
645 initrd = instance["initrd_path"]
646 buf.write(" initrd: %s\n" % initrd)
647 buf.write(" HVM boot order: %s\n" % instance["hvm_boot_order"])
648 buf.write(" Hardware:\n")
649 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
650 buf.write(" - memory: %dMiB\n" % instance["memory"])
651 buf.write(" - NICs: %s\n" %
652 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
654 for mac, ip, bridge in instance["nics"]]))
655 buf.write(" Block devices:\n")
657 for device in instance["disks"]:
658 _FormatBlockDevInfo(buf, device, 1)
660 logger.ToStdout(buf.getvalue().rstrip('\n'))
664 def SetInstanceParms(opts, args):
665 """Modifies an instance.
667 All parameters take effect only at the next restart of the instance.
670 opts - class with options as members
671 args - list with a single element, the instance name
673 memory - the new memory size
674 vcpus - the new number of cpus
675 mac - the new MAC address of the instance
678 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
679 opts.kernel_path or opts.initrd_path or opts.hvm_boot_order):
680 logger.ToStdout("Please give at least one of the parameters.")
683 kernel_path = _TransformPath(opts.kernel_path)
684 initrd_path = _TransformPath(opts.initrd_path)
685 if opts.hvm_boot_order == 'default':
686 hvm_boot_order = constants.VALUE_DEFAULT
688 hvm_boot_order = opts.hvm_boot_order
690 op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
691 vcpus=opts.vcpus, ip=opts.ip,
692 bridge=opts.bridge, mac=opts.mac,
693 kernel_path=opts.kernel_path,
694 initrd_path=opts.initrd_path,
695 hvm_boot_order=hvm_boot_order)
696 result = SubmitOpCode(op)
699 logger.ToStdout("Modified instance %s" % args[0])
700 for param, data in result:
701 logger.ToStdout(" - %-5s -> %s" % (param, data))
702 logger.ToStdout("Please don't forget that these parameters take effect"
703 " only at the next start of the instance.")
707 # options used in more than one cmd
708 node_opt = make_option("-n", "--node", dest="node", help="Target node",
711 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
714 # multi-instance selection options
715 m_force_multi = make_option("--force-multiple", dest="force_multi",
716 help="Do not ask for confirmation when more than"
717 " one instance is affected",
718 action="store_true", default=False)
720 m_pri_node_opt = make_option("--primary", dest="multi_mode",
721 help="Filter by nodes (primary only)",
722 const=_SHUTDOWN_NODES_PRI, action="store_const")
724 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
725 help="Filter by nodes (secondary only)",
726 const=_SHUTDOWN_NODES_SEC, action="store_const")
728 m_node_opt = make_option("--node", dest="multi_mode",
729 help="Filter by nodes (primary and secondary)",
730 const=_SHUTDOWN_NODES_BOTH, action="store_const")
732 m_clust_opt = make_option("--all", dest="multi_mode",
733 help="Select all instances in the cluster",
734 const=_SHUTDOWN_CLUSTER, action="store_const")
736 m_inst_opt = make_option("--instance", dest="multi_mode",
737 help="Filter by instance name [default]",
738 const=_SHUTDOWN_INSTANCES, action="store_const")
741 # this is defined separately due to readability only
744 make_option("-n", "--node", dest="node",
745 help="Target node and optional secondary node",
746 metavar="<pnode>[:<snode>]"),
747 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
749 default=20 * 1024, type="unit", metavar="<size>"),
750 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
752 default=4 * 1024, type="unit", metavar="<size>"),
754 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
755 default=128, type="unit", metavar="<mem>"),
756 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
757 default=1, type="int", metavar="<PROC>"),
758 make_option("-t", "--disk-template", dest="disk_template",
759 help="Custom disk setup (diskless, plain, local_raid1,"
760 " remote_raid1 or drbd)", default=None, metavar="TEMPL"),
761 make_option("-i", "--ip", dest="ip",
762 help="IP address ('none' [default], 'auto', or specify address)",
763 default='none', type="string", metavar="<ADDRESS>"),
764 make_option("--mac", dest="mac",
765 help="MAC address ('auto' [default], or specify address)",
766 default='auto', type="string", metavar="<MACADDRESS>"),
767 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
768 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
769 make_option("-b", "--bridge", dest="bridge",
770 help="Bridge to connect this instance to",
771 default=None, metavar="<bridge>"),
772 make_option("--no-start", dest="start", default=True,
773 action="store_false", help="Don't start the instance after"
775 make_option("--no-ip-check", dest="ip_check", default=True,
776 action="store_false", help="Don't check that the instance's IP"
777 " is alive (only valid with --no-start)"),
778 make_option("--kernel", dest="kernel_path",
779 help="Path to the instances' kernel (or 'default')",
781 type="string", metavar="<FILENAME>"),
782 make_option("--initrd", dest="initrd_path",
783 help="Path to the instances' initrd (or 'none', or 'default')",
785 type="string", metavar="<FILENAME>"),
786 make_option("--hvm-boot-order", dest="hvm_boot_order",
787 help="boot device order for HVM (one or more of [acdn])",
788 default=None, type="string", metavar="<BOOTORDER>"),
792 'add': (AddInstance, ARGS_ONE, add_opts,
794 "Creates and adds a new instance to the cluster"),
795 'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
796 [DEBUG_OPT, node_opt,
797 make_option("-b", "--disk", dest="disk", metavar="sdX",
798 help=("The name of the instance disk for which to"
799 " add the mirror"))],
800 "-n node -b disk <instance>",
801 "Creates a new mirror for the instance"),
802 'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT],
804 "Opens a console on the specified instance"),
805 'failover': (FailoverInstance, ARGS_ONE,
806 [DEBUG_OPT, FORCE_OPT,
807 make_option("--ignore-consistency", dest="ignore_consistency",
808 action="store_true", default=False,
809 help="Ignore the consistency of the disks on"
813 "Stops the instance and starts it on the backup node, using"
814 " the remote mirror (only for instances of type remote_raid1)"),
815 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
816 "Show information on the specified instance"),
817 'list': (ListInstances, ARGS_NONE,
818 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT], "",
819 "Lists the instances and their status. The available fields are"
820 " (see the man page for details): status, oper_state, oper_ram,"
821 " name, os, pnode, snodes, admin_state, admin_ram, disk_template,"
822 " ip, mac, bridge, sda_size, sdb_size, vcpus. The default field"
823 " list is (in order): name, os, pnode, status,"
825 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
826 "[-f] <instance>", "Reinstall a stopped instance"),
827 'remove': (RemoveInstance, ARGS_ONE,
828 [DEBUG_OPT, FORCE_OPT,
829 make_option("--ignore-failures", dest="ignore_failures",
830 action="store_true", default=False,
831 help=("Remove the instance from the cluster even"
832 " if there are failures during the removal"
833 " process (shutdown, disk removal, etc.)")),
835 "[-f] <instance>", "Shuts down the instance and removes it"),
836 'remove-mirror': (RemoveMDDRBDComponent, ARGS_ONE,
837 [DEBUG_OPT, node_opt,
838 make_option("-b", "--disk", dest="disk", metavar="sdX",
839 help=("The name of the instance disk"
840 " for which to add the mirror")),
841 make_option("-p", "--port", dest="port", metavar="PORT",
842 help=("The port of the drbd device"
843 " which to remove from the mirror"),
846 "-b disk -p port <instance>",
847 "Removes a mirror from the instance"),
848 'rename': (RenameInstance, ARGS_FIXED(2),
850 make_option("--no-ip-check", dest="ignore_ip",
851 help="Do not check that the IP of the new name"
853 default=False, action="store_true"),
855 "<instance> <new_name>", "Rename the instance"),
856 'replace-disks': (ReplaceDisks, ARGS_ONE,
858 make_option("-n", "--new-secondary", dest="new_secondary",
859 help=("New secondary node (for secondary"
860 " node change)"), metavar="NODE"),
861 make_option("-p", "--on-primary", dest="on_primary",
862 default=False, action="store_true",
863 help=("Replace the disk(s) on the primary"
864 " node (only for the drbd template)")),
865 make_option("-s", "--on-secondary", dest="on_secondary",
866 default=False, action="store_true",
867 help=("Replace the disk(s) on the secondary"
868 " node (only for the drbd template)")),
869 make_option("--disks", dest="disks", default=None,
870 help=("Comma-separated list of disks"
871 " to replace (e.g. sda) (optional,"
872 " defaults to all disks")),
874 "[-n NODE] <instance>",
875 "Replaces all disks for the instance"),
876 'modify': (SetInstanceParms, ARGS_ONE,
877 [DEBUG_OPT, FORCE_OPT,
878 cli_option("-m", "--memory", dest="mem",
880 default=None, type="unit", metavar="<mem>"),
881 make_option("-p", "--cpu", dest="vcpus",
882 help="Number of virtual CPUs",
883 default=None, type="int", metavar="<PROC>"),
884 make_option("-i", "--ip", dest="ip",
885 help="IP address ('none' or numeric IP)",
886 default=None, type="string", metavar="<ADDRESS>"),
887 make_option("-b", "--bridge", dest="bridge",
888 help="Bridge to connect this instance to",
889 default=None, type="string", metavar="<bridge>"),
890 make_option("--mac", dest="mac",
891 help="MAC address", default=None,
892 type="string", metavar="<MACADDRESS>"),
893 make_option("--kernel", dest="kernel_path",
894 help="Path to the instances' kernel (or"
895 " 'default')", default=None,
896 type="string", metavar="<FILENAME>"),
897 make_option("--initrd", dest="initrd_path",
898 help="Path to the instances' initrd (or 'none', or"
899 " 'default')", default=None,
900 type="string", metavar="<FILENAME>"),
901 make_option("--hvm-boot-order", dest="hvm_boot_order",
902 help="boot device order for HVM"
903 "(either one or more of [acdn] or 'default')",
904 default=None, type="string", metavar="<BOOTORDER>"),
906 "<instance>", "Alters the parameters of an instance"),
907 'shutdown': (ShutdownInstance, ARGS_ANY,
908 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
909 m_clust_opt, m_inst_opt, m_force_multi],
910 "<instance>", "Stops an instance"),
911 'startup': (StartupInstance, ARGS_ANY,
912 [DEBUG_OPT, FORCE_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 m_node_opt, m_pri_node_opt, m_sec_node_opt,
917 m_clust_opt, m_inst_opt,
919 "<instance>", "Starts an instance"),
921 'reboot': (RebootInstance, ARGS_ANY,
922 [DEBUG_OPT, m_force_multi,
923 make_option("-e", "--extra", dest="extra_args",
924 help="Extra arguments for the instance's kernel",
925 default=None, type="string", metavar="<PARAMS>"),
926 make_option("-t", "--type", dest="reboot_type",
927 help="Type of reboot: soft/hard/full",
928 default=constants.INSTANCE_REBOOT_SOFT,
929 type="string", metavar="<REBOOT>"),
930 make_option("--ignore-secondaries", dest="ignore_secondaries",
931 default=False, action="store_true",
932 help="Ignore errors from secondaries"),
933 m_node_opt, m_pri_node_opt, m_sec_node_opt,
934 m_clust_opt, m_inst_opt,
936 "<instance>", "Reboots an instance"),
937 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
939 "Activate an instance's disks"),
940 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
942 "Deactivate an instance's disks"),
943 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
944 "<node_name>", "List the tags of the given instance"),
945 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
946 "<node_name> tag...", "Add tags to the given instance"),
947 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
948 "<node_name> tag...", "Remove tags from given instance"),
952 'activate_block_devs': 'activate-disks',
953 'replace_disks': 'replace-disks',
958 if __name__ == '__main__':
959 sys.exit(GenericMain(commands, aliases=aliases,
960 override={"tag_type": constants.TAG_INSTANCE}))