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",
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"]
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)
263 def ReinstallInstance(opts, args):
264 """Reinstall an instance.
267 opts - class with options as members
268 args - list containing a single element, the instance name
271 instance_name = args[0]
274 usertext = ("This will reinstall the instance %s and remove"
275 " all data. Continue?") % instance_name
276 if not AskUser(usertext):
279 op = opcodes.OpReinstallInstance(instance_name=instance_name,
286 def RemoveInstance(opts, args):
287 """Remove an instance.
290 opts - class with options as members
291 args - list containing a single element, the instance name
294 instance_name = args[0]
298 usertext = ("This will remove the volumes of the instance %s"
299 " (including mirrors), thus removing all the data"
300 " of the instance. Continue?") % instance_name
301 if not AskUser(usertext):
304 op = opcodes.OpRemoveInstance(instance_name=instance_name,
305 ignore_failures=opts.ignore_failures)
310 def RenameInstance(opts, args):
311 """Rename an instance.
314 opts - class with options as members
315 args - list containing two elements, the instance name and the new name
318 op = opcodes.OpRenameInstance(instance_name=args[0],
320 ignore_ip=opts.ignore_ip)
326 def ActivateDisks(opts, args):
327 """Activate an instance's disks.
329 This serves two purposes:
330 - it allows one (as long as the instance is not running) to mount
331 the disks and modify them from the node
332 - it repairs inactive secondary drbds
335 instance_name = args[0]
336 op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
337 disks_info = SubmitOpCode(op)
338 for host, iname, nname in disks_info:
339 print "%s:%s:%s" % (host, iname, nname)
343 def DeactivateDisks(opts, args):
344 """Command-line interface for _ShutdownInstanceBlockDevices.
346 This function takes the instance name, looks for its primary node
347 and the tries to shutdown its block devices on that node.
350 instance_name = args[0]
351 op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
356 def StartupInstance(opts, args):
357 """Startup an instance.
360 opts - class with options as members
361 args - list containing a single element, the instance name
364 if opts.multi_mode is None:
365 opts.multi_mode = _SHUTDOWN_INSTANCES
366 inames = _ExpandMultiNames(opts.multi_mode, args)
368 raise errors.OpPrereqError("Selection filter does not match any instances")
369 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
370 if not (opts.force_multi or not multi_on
371 or _ConfirmOperation(inames, "startup")):
374 op = opcodes.OpStartupInstance(instance_name=name,
376 extra_args=opts.extra_args)
378 logger.ToStdout("Starting up %s" % name)
382 def RebootInstance(opts, args):
383 """Reboot an instance
386 opts - class with options as members
387 args - list containing a single element, the instance name
390 if opts.multi_mode is None:
391 opts.multi_mode = _SHUTDOWN_INSTANCES
392 inames = _ExpandMultiNames(opts.multi_mode, args)
394 raise errors.OpPrereqError("Selection filter does not match any instances")
395 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
396 if not (opts.force_multi or not multi_on
397 or _ConfirmOperation(inames, "reboot")):
400 op = opcodes.OpRebootInstance(instance_name=name,
401 reboot_type=opts.reboot_type,
402 ignore_secondaries=opts.ignore_secondaries)
407 def ShutdownInstance(opts, args):
408 """Shutdown an instance.
411 opts - class with options as members
412 args - list containing a single element, the instance name
415 if opts.multi_mode is None:
416 opts.multi_mode = _SHUTDOWN_INSTANCES
417 inames = _ExpandMultiNames(opts.multi_mode, args)
419 raise errors.OpPrereqError("Selection filter does not match any instances")
420 multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
421 if not (opts.force_multi or not multi_on
422 or _ConfirmOperation(inames, "shutdown")):
425 op = opcodes.OpShutdownInstance(instance_name=name)
427 logger.ToStdout("Shutting down %s" % name)
432 def AddMDDRBDComponent(opts, args):
433 """Add a new component to a remote_raid1 disk.
436 opts - class with options as members
437 args - list with a single element, the instance name
440 op = opcodes.OpAddMDDRBDComponent(instance_name=args[0],
442 remote_node=opts.node)
447 def RemoveMDDRBDComponent(opts, args):
448 """Remove a component from a remote_raid1 disk.
451 opts - class with options as members
452 args - list with a single element, the instance name
455 op = opcodes.OpRemoveMDDRBDComponent(instance_name=args[0],
462 def ReplaceDisks(opts, args):
463 """Replace the disks of an instance
466 opts - class with options as members
467 args - list with a single element, the instance name
470 instance_name = args[0]
471 new_2ndary = opts.new_secondary
472 if opts.disks is None:
473 disks = ["sda", "sdb"]
475 disks = opts.disks.split(",")
476 if opts.on_primary == opts.on_secondary: # no -p or -s passed, or both passed
477 mode = constants.REPLACE_DISK_ALL
478 elif opts.on_primary: # only on primary:
479 mode = constants.REPLACE_DISK_PRI
480 if new_2ndary is not None:
481 raise errors.OpPrereqError("Can't change secondary node on primary disk"
483 elif opts.on_secondary is not None: # only on secondary
484 mode = constants.REPLACE_DISK_SEC
486 op = opcodes.OpReplaceDisks(instance_name=args[0], disks=disks,
487 remote_node=new_2ndary, mode=mode)
492 def FailoverInstance(opts, args):
493 """Failover an instance.
495 The failover is done by shutting it down on its present node and
496 starting it on the secondary.
499 opts - class with options as members
500 args - list with a single element, the instance name
502 force - whether to failover without asking questions.
505 instance_name = args[0]
509 usertext = ("Failover will happen to image %s."
510 " This requires a shutdown of the instance. Continue?" %
512 if not AskUser(usertext):
515 op = opcodes.OpFailoverInstance(instance_name=instance_name,
516 ignore_consistency=opts.ignore_consistency)
521 def ConnectToInstanceConsole(opts, args):
522 """Connect to the console of an instance.
525 opts - class with options as members
526 args - list with a single element, the instance name
529 instance_name = args[0]
531 op = opcodes.OpConnectConsole(instance_name=instance_name)
532 cmd, argv = SubmitOpCode(op)
533 # drop lock and exec so other commands can run while we have console
538 sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
539 (cmd, " ".join(argv)))
543 def _FormatBlockDevInfo(buf, dev, indent_level):
544 """Show block device information.
546 This is only used by ShowInstanceConfig(), but it's too big to be
547 left for an inline definition.
550 def helper(buf, dtype, status):
551 """Format one line for phsyical device status."""
553 buf.write("not active\n")
555 (path, major, minor, syncp, estt, degr, ldisk) = status
556 buf.write("%s (%d:%d)" % (path, major, minor))
557 if dtype in (constants.LD_MD_R1, constants.LD_DRBD7, constants.LD_DRBD8):
558 if syncp is not None:
559 sync_text = "*RECOVERING* %5.2f%%," % syncp
561 sync_text += " ETA %ds" % estt
563 sync_text += " ETA unknown"
565 sync_text = "in sync"
567 degr_text = "*DEGRADED*"
571 ldisk_text = " *MISSING DISK*"
574 buf.write(" %s, status %s%s" % (sync_text, degr_text, ldisk_text))
575 elif dtype == constants.LD_LV:
577 ldisk_text = " *FAILED* (failed drive?)"
580 buf.write(ldisk_text)
583 if dev["iv_name"] is not None:
584 data = " - %s, " % dev["iv_name"]
587 data += "type: %s" % dev["dev_type"]
588 if dev["logical_id"] is not None:
589 data += ", logical_id: %s" % (dev["logical_id"],)
590 elif dev["physical_id"] is not None:
591 data += ", physical_id: %s" % (dev["physical_id"],)
592 buf.write("%*s%s\n" % (2*indent_level, "", data))
593 buf.write("%*s primary: " % (2*indent_level, ""))
594 helper(buf, dev["dev_type"], dev["pstatus"])
597 buf.write("%*s secondary: " % (2*indent_level, ""))
598 helper(buf, dev["dev_type"], dev["sstatus"])
601 for child in dev["children"]:
602 _FormatBlockDevInfo(buf, child, indent_level+1)
605 def ShowInstanceConfig(opts, args):
606 """Compute instance run-time status.
610 op = opcodes.OpQueryInstanceData(instances=args)
611 result = SubmitOpCode(op)
614 logger.ToStdout("No instances.")
619 for instance_name in result:
620 instance = result[instance_name]
621 buf.write("Instance name: %s\n" % instance["name"])
622 buf.write("State: configured to be %s, actual state is %s\n" %
623 (instance["config_state"], instance["run_state"]))
624 buf.write(" Nodes:\n")
625 buf.write(" - primary: %s\n" % instance["pnode"])
626 buf.write(" - secondaries: %s\n" % ", ".join(instance["snodes"]))
627 buf.write(" Operating system: %s\n" % instance["os"])
628 buf.write(" Allocated network port: %s\n" % instance["network_port"])
629 if instance["kernel_path"] in (None, constants.VALUE_DEFAULT):
630 kpath = "(default: %s)" % constants.XEN_KERNEL
632 kpath = instance["kernel_path"]
633 buf.write(" Kernel path: %s\n" % kpath)
634 if instance["initrd_path"] in (None, constants.VALUE_DEFAULT):
635 initrd = "(default: %s)" % constants.XEN_INITRD
636 elif instance["initrd_path"] == constants.VALUE_NONE:
639 initrd = instance["initrd_path"]
640 buf.write(" initrd: %s\n" % initrd)
641 buf.write(" Hardware:\n")
642 buf.write(" - VCPUs: %d\n" % instance["vcpus"])
643 buf.write(" - memory: %dMiB\n" % instance["memory"])
644 buf.write(" - NICs: %s\n" %
645 ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
647 for mac, ip, bridge in instance["nics"]]))
648 buf.write(" Block devices:\n")
650 for device in instance["disks"]:
651 _FormatBlockDevInfo(buf, device, 1)
653 logger.ToStdout(buf.getvalue().rstrip('\n'))
657 def SetInstanceParms(opts, args):
658 """Modifies an instance.
660 All parameters take effect only at the next restart of the instance.
663 opts - class with options as members
664 args - list with a single element, the instance name
666 memory - the new memory size
667 vcpus - the new number of cpus
668 mac - the new MAC address of the instance
671 if not (opts.mem or opts.vcpus or opts.ip or opts.bridge or opts.mac or
672 opts.kernel_path or opts.initrd_path):
673 logger.ToStdout("Please give at least one of the parameters.")
676 kernel_path = _TransformPath(opts.kernel_path)
677 initrd_path = _TransformPath(opts.initrd_path)
679 op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
680 vcpus=opts.vcpus, ip=opts.ip,
681 bridge=opts.bridge, mac=opts.mac,
682 kernel_path=opts.kernel_path,
683 initrd_path=opts.initrd_path)
684 result = SubmitOpCode(op)
687 logger.ToStdout("Modified instance %s" % args[0])
688 for param, data in result:
689 logger.ToStdout(" - %-5s -> %s" % (param, data))
690 logger.ToStdout("Please don't forget that these parameters take effect"
691 " only at the next start of the instance.")
695 # options used in more than one cmd
696 node_opt = make_option("-n", "--node", dest="node", help="Target node",
699 os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
702 # multi-instance selection options
703 m_force_multi = make_option("--force-multiple", dest="force_multi",
704 help="Do not ask for confirmation when more than"
705 " one instance is affected",
706 action="store_true", default=False)
708 m_pri_node_opt = make_option("--primary", dest="multi_mode",
709 help="Filter by nodes (primary only)",
710 const=_SHUTDOWN_NODES_PRI, action="store_const")
712 m_sec_node_opt = make_option("--secondary", dest="multi_mode",
713 help="Filter by nodes (secondary only)",
714 const=_SHUTDOWN_NODES_SEC, action="store_const")
716 m_node_opt = make_option("--node", dest="multi_mode",
717 help="Filter by nodes (primary and secondary)",
718 const=_SHUTDOWN_NODES_BOTH, action="store_const")
720 m_clust_opt = make_option("--all", dest="multi_mode",
721 help="Select all instances in the cluster",
722 const=_SHUTDOWN_CLUSTER, action="store_const")
724 m_inst_opt = make_option("--instance", dest="multi_mode",
725 help="Filter by instance name [default]",
726 const=_SHUTDOWN_INSTANCES, action="store_const")
729 # this is defined separately due to readability only
732 make_option("-n", "--node", dest="node",
733 help="Target node and optional secondary node",
734 metavar="<pnode>[:<snode>]"),
735 cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
737 default=20 * 1024, type="unit", metavar="<size>"),
738 cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
740 default=4 * 1024, type="unit", metavar="<size>"),
742 cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
743 default=128, type="unit", metavar="<mem>"),
744 make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
745 default=1, type="int", metavar="<PROC>"),
746 make_option("-t", "--disk-template", dest="disk_template",
747 help="Custom disk setup (diskless, plain, local_raid1,"
748 " remote_raid1 or drbd)", default=None, metavar="TEMPL"),
749 make_option("-i", "--ip", dest="ip",
750 help="IP address ('none' [default], 'auto', or specify address)",
751 default='none', type="string", metavar="<ADDRESS>"),
752 make_option("--mac", dest="mac",
753 help="MAC address ('auto' [default], or specify address)",
754 default='auto', type="string", metavar="<MACADDRESS>"),
755 make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
756 action="store_false", help="Don't wait for sync (DANGEROUS!)"),
757 make_option("-b", "--bridge", dest="bridge",
758 help="Bridge to connect this instance to",
759 default=None, metavar="<bridge>"),
760 make_option("--no-start", dest="start", default=True,
761 action="store_false", help="Don't start the instance after"
763 make_option("--no-ip-check", dest="ip_check", default=True,
764 action="store_false", help="Don't check that the instance's IP"
765 " is alive (only valid with --no-start)"),
766 make_option("--kernel", dest="kernel_path",
767 help="Path to the instances' kernel (or 'default')",
769 type="string", metavar="<FILENAME>"),
770 make_option("--initrd", dest="initrd_path",
771 help="Path to the instances' initrd (or 'none', or 'default')",
773 type="string", metavar="<FILENAME>"),
777 'add': (AddInstance, ARGS_ONE, add_opts,
779 "Creates and adds a new instance to the cluster"),
780 'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
781 [DEBUG_OPT, node_opt,
782 make_option("-b", "--disk", dest="disk", metavar="sdX",
783 help=("The name of the instance disk for which to"
784 " add the mirror"))],
785 "-n node -b disk <instance>",
786 "Creates a new mirror for the instance"),
787 'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT],
789 "Opens a console on the specified instance"),
790 'failover': (FailoverInstance, ARGS_ONE,
791 [DEBUG_OPT, FORCE_OPT,
792 make_option("--ignore-consistency", dest="ignore_consistency",
793 action="store_true", default=False,
794 help="Ignore the consistency of the disks on"
798 "Stops the instance and starts it on the backup node, using"
799 " the remote mirror (only for instances of type remote_raid1)"),
800 'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
801 "Show information on the specified instance"),
802 'list': (ListInstances, ARGS_NONE,
803 [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
804 "", "Lists the instances and their status"),
805 'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
806 "[-f] <instance>", "Reinstall the instance"),
807 'remove': (RemoveInstance, ARGS_ONE,
808 [DEBUG_OPT, FORCE_OPT,
809 make_option("--ignore-failures", dest="ignore_failures",
810 action="store_true", default=False,
811 help=("Remove the instance from the cluster even"
812 " if there are failures during the removal"
813 " process (shutdown, disk removal, etc.)")),
815 "[-f] <instance>", "Shuts down the instance and removes it"),
816 'remove-mirror': (RemoveMDDRBDComponent, ARGS_ONE,
817 [DEBUG_OPT, node_opt,
818 make_option("-b", "--disk", dest="disk", metavar="sdX",
819 help=("The name of the instance disk"
820 " for which to add the mirror")),
821 make_option("-p", "--port", dest="port", metavar="PORT",
822 help=("The port of the drbd device"
823 " which to remove from the mirror"),
826 "-b disk -p port <instance>",
827 "Removes a mirror from the instance"),
828 'rename': (RenameInstance, ARGS_FIXED(2),
830 make_option("--no-ip-check", dest="ignore_ip",
831 help="Do not check that the IP of the new name"
833 default=False, action="store_true"),
835 "<instance> <new_name>", "Rename the instance"),
836 'replace-disks': (ReplaceDisks, ARGS_ONE,
838 make_option("-n", "--new-secondary", dest="new_secondary",
839 help=("New secondary node (for secondary"
840 " node change)"), metavar="NODE"),
841 make_option("-p", "--on-primary", dest="on_primary",
842 default=False, action="store_true",
843 help=("Replace the disk(s) on the primary"
844 " node (only for the drbd template)")),
845 make_option("-s", "--on-secondary", dest="on_secondary",
846 default=False, action="store_true",
847 help=("Replace the disk(s) on the secondary"
848 " node (only for the drbd template)")),
849 make_option("--disks", dest="disks", default=None,
850 help=("Comma-separated list of disks"
851 " to replace (e.g. sda) (optional,"
852 " defaults to all disks")),
854 "[-n NODE] <instance>",
855 "Replaces all disks for the instance"),
856 'modify': (SetInstanceParms, ARGS_ONE,
857 [DEBUG_OPT, FORCE_OPT,
858 cli_option("-m", "--memory", dest="mem",
860 default=None, type="unit", metavar="<mem>"),
861 make_option("-p", "--cpu", dest="vcpus",
862 help="Number of virtual CPUs",
863 default=None, type="int", metavar="<PROC>"),
864 make_option("-i", "--ip", dest="ip",
865 help="IP address ('none' or numeric IP)",
866 default=None, type="string", metavar="<ADDRESS>"),
867 make_option("-b", "--bridge", dest="bridge",
868 help="Bridge to connect this instance to",
869 default=None, type="string", metavar="<bridge>"),
870 make_option("--mac", dest="mac",
871 help="MAC address", default=None,
872 type="string", metavar="<MACADDRESS>"),
873 make_option("--kernel", dest="kernel_path",
874 help="Path to the instances' kernel (or"
875 " 'default')", default=None,
876 type="string", metavar="<FILENAME>"),
877 make_option("--initrd", dest="initrd_path",
878 help="Path to the instances' initrd (or 'none', or"
879 " 'default')", default=None,
880 type="string", metavar="<FILENAME>"),
882 "<instance>", "Alters the parameters of an instance"),
883 'shutdown': (ShutdownInstance, ARGS_ANY,
884 [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
885 m_clust_opt, m_inst_opt, m_force_multi],
886 "<instance>", "Stops an instance"),
887 'startup': (StartupInstance, ARGS_ANY,
888 [DEBUG_OPT, FORCE_OPT, m_force_multi,
889 make_option("-e", "--extra", dest="extra_args",
890 help="Extra arguments for the instance's kernel",
891 default=None, type="string", metavar="<PARAMS>"),
892 m_node_opt, m_pri_node_opt, m_sec_node_opt,
893 m_clust_opt, m_inst_opt,
895 "<instance>", "Starts an instance"),
897 'reboot': (RebootInstance, ARGS_ANY,
898 [DEBUG_OPT, m_force_multi,
899 make_option("-e", "--extra", dest="extra_args",
900 help="Extra arguments for the instance's kernel",
901 default=None, type="string", metavar="<PARAMS>"),
902 make_option("-t", "--type", dest="reboot_type",
903 help="Type of reboot: soft/hard/full",
904 default=constants.INSTANCE_REBOOT_SOFT,
905 type="string", metavar="<REBOOT>"),
906 make_option("--ignore-secondaries", dest="ignore_secondaries",
907 default=False, action="store_true",
908 help="Ignore errors from secondaries"),
909 m_node_opt, m_pri_node_opt, m_sec_node_opt,
910 m_clust_opt, m_inst_opt,
912 "<instance>", "Reboots an instance"),
913 'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
915 "Activate an instance's disks"),
916 'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
918 "Deactivate an instance's disks"),
919 'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
920 "<node_name>", "List the tags of the given instance"),
921 'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
922 "<node_name> tag...", "Add tags to the given instance"),
923 'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
924 "<node_name> tag...", "Remove tags from given instance"),
927 if __name__ == '__main__':
928 sys.exit(GenericMain(commands,
929 override={"tag_type": constants.TAG_INSTANCE}))