Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ f5abe9bd

History | View | Annotate | Download (26.4 kB)

1
#!/usr/bin/python
2
#
3

    
4
# Copyright (C) 2006, 2007 Google Inc.
5
#
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.
10
#
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.
15
#
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
19
# 02110-1301, USA.
20

    
21

    
22
import sys
23
import os
24
import itertools
25
from optparse import make_option
26
from cStringIO import StringIO
27

    
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
34

    
35

    
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"
41

    
42
def _ExpandMultiNames(mode, names):
43
  """Expand the given names using the passed mode.
44

    
45
  Args:
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
51
      node1.example.com)
52

    
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
58
  returned.
59

    
60
  """
61
  if mode == _SHUTDOWN_CLUSTER:
62
    if names:
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]
67

    
68
  elif mode in (_SHUTDOWN_NODES_BOTH,
69
                _SHUTDOWN_NODES_PRI,
70
                _SHUTDOWN_NODES_SEC):
71
    if not names:
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:
83
      inames = pri_names
84
    elif mode == _SHUTDOWN_NODES_SEC:
85
      inames = sec_names
86
    else:
87
      raise errors.ProgrammerError("Unhandled shutdown type")
88

    
89
  elif mode == _SHUTDOWN_INSTANCES:
90
    if not names:
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]
95

    
96
  else:
97
    raise errors.OpPrereqError("Unknown mode '%s'" % mode)
98

    
99
  return inames
100

    
101

    
102
def _ConfirmOperation(inames, text):
103
  """Ask the user to confirm an operation on a list of instances.
104

    
105
  This function is used to request confirmation for doing an operation
106
  on a given list of instances.
107

    
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').
111

    
112
  Returns: boolean depending on user's confirmation.
113

    
114
  """
115
  count = len(inames)
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]))
120

    
121
  choices = [('y', True, 'Yes, execute the %s' % text),
122
             ('n', False, 'No, abort the %s' % text)]
123

    
124
  if count > 20:
125
    choices.insert(1, ('v', 'v', 'View the list of affected instances'))
126
    ask = msg
127
  else:
128
    ask = msg + affected
129

    
130
  choice = AskUser(ask, choices)
131
  if choice == 'v':
132
    choices.pop(1)
133
    choice = AskUser(choices, msg + affected)
134
  return choice
135

    
136

    
137
def ListInstances(opts, args):
138
  """List instances and their properties.
139

    
140
  """
141
  if opts.output is None:
142
    selected_fields = ["name", "os", "pnode", "admin_state",
143
                       "oper_state", "oper_ram"]
144
  else:
145
    selected_fields = opts.output.split(",")
146

    
147
  op = opcodes.OpQueryInstances(output_fields=selected_fields, names=[])
148
  output = SubmitOpCode(op)
149

    
150
  if not opts.no_headers:
151
    headers = {"name": "Instance", "os": "OS", "pnode": "Primary_node",
152
               "snodes": "Secondary_Nodes", "admin_state": "Autostart",
153
               "oper_state": "Status", "admin_ram": "Configured_memory",
154
               "oper_ram": "Memory", "disk_template": "Disk_template",
155
               "ip": "IP Address", "mac": "MAC Address",
156
               "bridge": "Bridge",
157
               "sda_size": "Disk/0", "sdb_size": "Disk/1"}
158
  else:
159
    headers = None
160

    
161
  if opts.human_readable:
162
    unitfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
163
  else:
164
    unitfields = None
165

    
166
  numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
167

    
168
  # change raw values to nicer strings
169
  for row in output:
170
    for idx, field in enumerate(selected_fields):
171
      val = row[idx]
172
      if field == "snodes":
173
        val = ",".join(val) or "-"
174
      elif field == "admin_state":
175
        if val:
176
          val = "yes"
177
        else:
178
          val = "no"
179
      elif field == "oper_state":
180
        if val is None:
181
          val = "(node down)"
182
        elif val: # True
183
          val = "running"
184
        else:
185
          val = "stopped"
186
      elif field == "oper_ram":
187
        if val is None:
188
          val = "(node down)"
189
      elif field == "sda_size" or field == "sdb_size":
190
        if val is None:
191
          val = "N/A"
192
      row[idx] = str(val)
193

    
194
  data = GenerateTable(separator=opts.separator, headers=headers,
195
                       fields=selected_fields, unitfields=unitfields,
196
                       numfields=numfields, data=output)
197

    
198
  for line in data:
199
    logger.ToStdout(line)
200

    
201
  return 0
202

    
203

    
204
def AddInstance(opts, args):
205
  """Add an instance to the cluster.
206

    
207
  Args:
208
    opts - class with options as members
209
    args - list with a single element, the instance name
210
  Opts used:
211
    mem - amount of memory to allocate to instance (MiB)
212
    size - amount of disk space to allocate to instance (MiB)
213
    os - which OS to run on instance
214
    node - node to run new instance on
215

    
216
  """
217
  instance = args[0]
218

    
219
  op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
220
                                disk_size=opts.size, swap_size=opts.swap,
221
                                disk_template=opts.disk_template,
222
                                mode=constants.INSTANCE_CREATE,
223
                                os_type=opts.os, pnode=opts.node,
224
                                snode=opts.snode, vcpus=opts.vcpus,
225
                                ip=opts.ip, bridge=opts.bridge,
226
                                start=opts.start, ip_check=opts.ip_check,
227
                                wait_for_sync=opts.wait_for_sync)
228
  SubmitOpCode(op)
229
  return 0
230

    
231

    
232
def ReinstallInstance(opts, args):
233
  """Reinstall an instance.
234

    
235
  Args:
236
    opts - class with options as members
237
    args - list containing a single element, the instance name
238

    
239
  """
240
  instance_name = args[0]
241

    
242
  if not opts.force:
243
    usertext = ("This will reinstall the instance %s and remove "
244
                "all data. Continue?") % instance_name
245
    if not AskUser(usertext):
246
      return 1
247

    
248
  op = opcodes.OpReinstallInstance(instance_name=instance_name,
249
                                   os_type=opts.os)
250
  SubmitOpCode(op)
251

    
252
  return 0
253

    
254

    
255
def RemoveInstance(opts, args):
256
  """Remove an instance.
257

    
258
  Args:
259
    opts - class with options as members
260
    args - list containing a single element, the instance name
261

    
262
  """
263
  instance_name = args[0]
264
  force = opts.force
265

    
266
  if not force:
267
    usertext = ("This will remove the volumes of the instance %s"
268
                " (including mirrors), thus removing all the data"
269
                " of the instance. Continue?") % instance_name
270
    if not AskUser(usertext):
271
      return 1
272

    
273
  op = opcodes.OpRemoveInstance(instance_name=instance_name)
274
  SubmitOpCode(op)
275
  return 0
276

    
277

    
278
def RenameInstance(opts, args):
279
  """Rename an instance.
280

    
281
  Args:
282
    opts - class with options as members
283
    args - list containing two elements, the instance name and the new name
284

    
285
  """
286
  op = opcodes.OpRenameInstance(instance_name=args[0],
287
                                new_name=args[1],
288
                                ignore_ip=opts.ignore_ip)
289
  SubmitOpCode(op)
290

    
291
  return 0
292

    
293

    
294
def ActivateDisks(opts, args):
295
  """Activate an instance's disks.
296

    
297
  This serves two purposes:
298
    - it allows one (as long as the instance is not running) to mount
299
    the disks and modify them from the node
300
    - it repairs inactive secondary drbds
301

    
302
  """
303
  instance_name = args[0]
304
  op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
305
  disks_info = SubmitOpCode(op)
306
  for host, iname, nname in disks_info:
307
    print "%s:%s:%s" % (host, iname, nname)
308
  return 0
309

    
310

    
311
def DeactivateDisks(opts, args):
312
  """Command-line interface for _ShutdownInstanceBlockDevices.
313

    
314
  This function takes the instance name, looks for its primary node
315
  and the tries to shutdown its block devices on that node.
316

    
317
  """
318
  instance_name = args[0]
319
  op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
320
  SubmitOpCode(op)
321
  return 0
322

    
323

    
324
def StartupInstance(opts, args):
325
  """Startup an instance.
326

    
327
  Args:
328
    opts - class with options as members
329
    args - list containing a single element, the instance name
330

    
331
  """
332
  if opts.multi_mode is None:
333
    opts.multi_mode = _SHUTDOWN_INSTANCES
334
  inames = _ExpandMultiNames(opts.multi_mode, args)
335
  multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
336
  if not (opts.force_multi or not multi_on
337
          or _ConfirmOperation(inames, "startup")):
338
    return 1
339
  for name in inames:
340
    op = opcodes.OpStartupInstance(instance_name=name,
341
                                   force=opts.force,
342
                                   extra_args=opts.extra_args)
343
    if multi_on:
344
      logger.ToStdout("Starting up %s" % name)
345
    SubmitOpCode(op)
346
  return 0
347

    
348

    
349
def ShutdownInstance(opts, args):
350
  """Shutdown an instance.
351

    
352
  Args:
353
    opts - class with options as members
354
    args - list containing a single element, the instance name
355

    
356
  """
357
  if opts.multi_mode is None:
358
    opts.multi_mode = _SHUTDOWN_INSTANCES
359
  inames = _ExpandMultiNames(opts.multi_mode, args)
360
  multi_on = opts.multi_mode != _SHUTDOWN_INSTANCES or len(inames) > 1
361
  if not (opts.force_multi or not multi_on
362
          or _ConfirmOperation(inames, "shutdown")):
363
    return 1
364
  for name in inames:
365
    op = opcodes.OpShutdownInstance(instance_name=name)
366
    if multi_on:
367
      logger.ToStdout("Shutting down %s" % name)
368
    SubmitOpCode(op)
369
  return 0
370

    
371

    
372
def AddMDDRBDComponent(opts, args):
373
  """Add a new component to a remote_raid1 disk.
374

    
375
  Args:
376
    opts - class with options as members
377
    args - list with a single element, the instance name
378

    
379
  """
380
  op = opcodes.OpAddMDDRBDComponent(instance_name=args[0],
381
                                    disk_name=opts.disk,
382
                                    remote_node=opts.node)
383
  SubmitOpCode(op)
384
  return 0
385

    
386

    
387
def RemoveMDDRBDComponent(opts, args):
388
  """Remove a component from a remote_raid1 disk.
389

    
390
  Args:
391
    opts - class with options as members
392
    args - list with a single element, the instance name
393

    
394
  """
395
  op = opcodes.OpRemoveMDDRBDComponent(instance_name=args[0],
396
                                       disk_name=opts.disk,
397
                                       disk_id=opts.port)
398
  SubmitOpCode(op)
399
  return 0
400

    
401

    
402
def ReplaceDisks(opts, args):
403
  """Replace the disks of an instance
404

    
405
  Args:
406
    opts - class with options as members
407
    args - list with a single element, the instance name
408

    
409
  """
410
  instance_name = args[0]
411
  new_secondary = opts.new_secondary
412
  op = opcodes.OpReplaceDisks(instance_name=args[0],
413
                              remote_node=opts.new_secondary)
414
  SubmitOpCode(op)
415
  return 0
416

    
417

    
418
def FailoverInstance(opts, args):
419
  """Failover an instance.
420

    
421
  The failover is done by shutting it down on its present node and
422
  starting it on the secondary.
423

    
424
  Args:
425
    opts - class with options as members
426
    args - list with a single element, the instance name
427
  Opts used:
428
    force - whether to failover without asking questions.
429

    
430
  """
431
  instance_name = args[0]
432
  force = opts.force
433

    
434
  if not force:
435
    usertext = ("Failover will happen to image %s."
436
                " This requires a shutdown of the instance. Continue?" %
437
                (instance_name,))
438
    if not AskUser(usertext):
439
      return 1
440

    
441
  op = opcodes.OpFailoverInstance(instance_name=instance_name,
442
                                  ignore_consistency=opts.ignore_consistency)
443
  SubmitOpCode(op)
444
  return 0
445

    
446

    
447
def ConnectToInstanceConsole(opts, args):
448
  """Connect to the console of an instance.
449

    
450
  Args:
451
    opts - class with options as members
452
    args - list with a single element, the instance name
453

    
454
  """
455
  instance_name = args[0]
456

    
457
  op = opcodes.OpConnectConsole(instance_name=instance_name)
458
  cmd, argv = SubmitOpCode(op)
459
  # drop lock and exec so other commands can run while we have console
460
  utils.Unlock("cmd")
461
  try:
462
    os.execvp(cmd, argv)
463
  finally:
464
    sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
465
                     (cmd, " ".join(argv)))
466
    os._exit(1)
467

    
468

    
469
def _FormatBlockDevInfo(buf, dev, indent_level):
470
  """Show block device information.
471

    
472
  This is only used by ShowInstanceConfig(), but it's too big to be
473
  left for an inline definition.
474

    
475
  """
476
  def helper(buf, dtype, status):
477
    """Format one line for phsyical device status."""
478
    if not status:
479
      buf.write("not active\n")
480
    else:
481
      (path, major, minor, syncp, estt, degr) = status
482
      buf.write("%s (%d:%d)" % (path, major, minor))
483
      if dtype in ("md_raid1", "drbd"):
484
        if syncp is not None:
485
          sync_text = "*RECOVERING* %5.2f%%," % syncp
486
          if estt:
487
            sync_text += " ETA %ds" % estt
488
          else:
489
            sync_text += " ETA unknown"
490
        else:
491
          sync_text = "in sync"
492
        if degr:
493
          degr_text = "*DEGRADED*"
494
        else:
495
          degr_text = "ok"
496
        buf.write(" %s, status %s" % (sync_text, degr_text))
497
      buf.write("\n")
498

    
499
  if dev["iv_name"] is not None:
500
    data = "  - %s, " % dev["iv_name"]
501
  else:
502
    data = "  - "
503
  data += "type: %s" % dev["dev_type"]
504
  if dev["logical_id"] is not None:
505
    data += ", logical_id: %s" % (dev["logical_id"],)
506
  elif dev["physical_id"] is not None:
507
    data += ", physical_id: %s" % (dev["physical_id"],)
508
  buf.write("%*s%s\n" % (2*indent_level, "", data))
509
  buf.write("%*s    primary:   " % (2*indent_level, ""))
510
  helper(buf, dev["dev_type"], dev["pstatus"])
511

    
512
  if dev["sstatus"]:
513
    buf.write("%*s    secondary: " % (2*indent_level, ""))
514
    helper(buf, dev["dev_type"], dev["sstatus"])
515

    
516
  if dev["children"]:
517
    for child in dev["children"]:
518
      _FormatBlockDevInfo(buf, child, indent_level+1)
519

    
520

    
521
def ShowInstanceConfig(opts, args):
522
  """Compute instance run-time status.
523

    
524
  """
525
  retcode = 0
526
  op = opcodes.OpQueryInstanceData(instances=args)
527
  result = SubmitOpCode(op)
528

    
529
  if not result:
530
    logger.ToStdout("No instances.")
531
    return 1
532

    
533
  buf = StringIO()
534
  retcode = 0
535
  for instance_name in result:
536
    instance = result[instance_name]
537
    buf.write("Instance name: %s\n" % instance["name"])
538
    buf.write("State: configured to be %s, actual state is %s\n" %
539
              (instance["config_state"], instance["run_state"]))
540
    buf.write("  Nodes:\n")
541
    buf.write("    - primary: %s\n" % instance["pnode"])
542
    buf.write("    - secondaries: %s\n" % ", ".join(instance["snodes"]))
543
    buf.write("  Operating system: %s\n" % instance["os"])
544
    buf.write("  Hardware:\n")
545
    buf.write("    - memory: %dMiB\n" % instance["memory"])
546
    buf.write("    - NICs: %s\n" %
547
        ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
548
                   (mac, ip, bridge)
549
                     for mac, ip, bridge in instance["nics"]]))
550
    buf.write("  Block devices:\n")
551

    
552
    for device in instance["disks"]:
553
      _FormatBlockDevInfo(buf, device, 1)
554

    
555
  logger.ToStdout(buf.getvalue().rstrip('\n'))
556
  return retcode
557

    
558

    
559
def SetInstanceParms(opts, args):
560
  """Modifies an instance.
561

    
562
  All parameters take effect only at the next restart of the instance.
563

    
564
  Args:
565
    opts - class with options as members
566
    args - list with a single element, the instance name
567
  Opts used:
568
    memory - the new memory size
569
    vcpus - the new number of cpus
570

    
571
  """
572
  if not opts.mem and not opts.vcpus and not opts.ip and not opts.bridge:
573
    logger.ToStdout("Please give at least one of the parameters.")
574
    return 1
575

    
576
  op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
577
                                  vcpus=opts.vcpus, ip=opts.ip,
578
                                  bridge=opts.bridge)
579
  result = SubmitOpCode(op)
580

    
581
  if result:
582
    logger.ToStdout("Modified instance %s" % args[0])
583
    for param, data in result:
584
      logger.ToStdout(" - %-5s -> %s" % (param, data))
585
    logger.ToStdout("Please don't forget that these parameters take effect"
586
                    " only at the next start of the instance.")
587
  return 0
588

    
589

    
590
# options used in more than one cmd
591
node_opt = make_option("-n", "--node", dest="node", help="Target node",
592
                       metavar="<node>")
593

    
594
os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
595
                    metavar="<os>")
596

    
597
# multi-instance selection options
598
m_force_multi = make_option("--force-multiple", dest="force_multi",
599
                            help="Do not ask for confirmation when more than"
600
                            " one instance is affected",
601
                            action="store_true", default=False)
602

    
603
m_pri_node_opt = make_option("--primary", dest="multi_mode",
604
                             help="Filter by nodes (primary only)",
605
                             const=_SHUTDOWN_NODES_PRI, action="store_const")
606

    
607
m_sec_node_opt = make_option("--secondary", dest="multi_mode",
608
                             help="Filter by nodes (secondary only)",
609
                             const=_SHUTDOWN_NODES_SEC, action="store_const")
610

    
611
m_node_opt = make_option("--node", dest="multi_mode",
612
                         help="Filter by nodes (primary and secondary)",
613
                         const=_SHUTDOWN_NODES_BOTH, action="store_const")
614

    
615
m_clust_opt = make_option("--all", dest="multi_mode",
616
                          help="Select all instances in the cluster",
617
                          const=_SHUTDOWN_CLUSTER, action="store_const")
618

    
619
m_inst_opt = make_option("--instance", dest="multi_mode",
620
                         help="Filter by instance name [default]",
621
                         const=_SHUTDOWN_INSTANCES, action="store_const")
622

    
623

    
624
# this is defined separately due to readability only
625
add_opts = [
626
  DEBUG_OPT,
627
  node_opt,
628
  cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
629
             " a suffix is used",
630
             default=20 * 1024, type="unit", metavar="<size>"),
631
  cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
632
             " suffix is used",
633
             default=4 * 1024, type="unit", metavar="<size>"),
634
  os_opt,
635
  cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
636
              default=128, type="unit", metavar="<mem>"),
637
  make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
638
              default=1, type="int", metavar="<PROC>"),
639
  make_option("-t", "--disk-template", dest="disk_template",
640
              help="Custom disk setup (diskless, plain, local_raid1 or"
641
              " remote_raid1)", default=None, metavar="TEMPL"),
642
  make_option("-i", "--ip", dest="ip",
643
              help="IP address ('none' [default], 'auto', or specify address)",
644
              default='none', type="string", metavar="<ADDRESS>"),
645
  make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
646
              action="store_false", help="Don't wait for sync (DANGEROUS!)"),
647
  make_option("--secondary-node", dest="snode",
648
              help="Secondary node for remote_raid1 disk layout",
649
              metavar="<node>"),
650
  make_option("-b", "--bridge", dest="bridge",
651
              help="Bridge to connect this instance to",
652
              default=None, metavar="<bridge>"),
653
  make_option("--no-start", dest="start", default=True,
654
              action="store_false", help="Don't start the instance after"
655
              " creation"),
656
  make_option("--no-ip-check", dest="ip_check", default=True,
657
              action="store_false", help="Don't check that the instance's IP"
658
              " is alive (only valid with --no-start)"),
659
  ]
660

    
661
commands = {
662
  'add': (AddInstance, ARGS_ONE, add_opts,
663
          "[opts...] <name>",
664
          "Creates and adds a new instance to the cluster"),
665
  'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
666
                [DEBUG_OPT, node_opt,
667
                 make_option("-b", "--disk", dest="disk", metavar="sdX",
668
                             help=("The name of the instance disk for which to"
669
                                   " add the mirror"))],
670
                "-n node -b disk <instance>",
671
                "Creates a new mirror for the instance"),
672
  'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT],
673
              "<instance>",
674
              "Opens a console on the specified instance"),
675
  'failover': (FailoverInstance, ARGS_ONE,
676
               [DEBUG_OPT, FORCE_OPT,
677
                make_option("--ignore-consistency", dest="ignore_consistency",
678
                            action="store_true", default=False,
679
                            help="Ignore the consistency of the disks on"
680
                            " the secondary"),
681
                ],
682
               "[-f] <instance>",
683
               "Stops the instance and starts it on the backup node, using"
684
               " the remote mirror (only for instances of type remote_raid1)"),
685
  'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
686
           "Show information on the specified instance"),
687
  'list': (ListInstances, ARGS_NONE,
688
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
689
           "", "Lists the instances and their status"),
690
  'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
691
                "[-f] <instance>", "Reinstall the instance"),
692
  'remove': (RemoveInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT],
693
             "[-f] <instance>", "Shuts down the instance and removes it"),
694
  'remove-mirror': (RemoveMDDRBDComponent, ARGS_ONE,
695
                   [DEBUG_OPT, node_opt,
696
                    make_option("-b", "--disk", dest="disk", metavar="sdX",
697
                                help=("The name of the instance disk"
698
                                      " for which to add the mirror")),
699
                    make_option("-p", "--port", dest="port", metavar="PORT",
700
                                help=("The port of the drbd device"
701
                                      " which to remove from the mirror"),
702
                                type="int"),
703
                    ],
704
                   "-b disk -p port <instance>",
705
                   "Removes a mirror from the instance"),
706
  'rename': (RenameInstance, ARGS_FIXED(2),
707
             [DEBUG_OPT,
708
              make_option("--no-ip-check", dest="ignore_ip",
709
                          help="Do not check that the IP of the new name"
710
                          " is alive",
711
                          default=False, action="store_true"),
712
              ],
713
             "<instance> <new_name>", "Rename the instance"),
714
  'replace-disks': (ReplaceDisks, ARGS_ONE,
715
                    [DEBUG_OPT,
716
                     make_option("-n", "--new-secondary", dest="new_secondary",
717
                                 metavar="NODE",
718
                                 help=("New secondary node (if you want to"
719
                                       " change the secondary)"))],
720
                    "[-n NODE] <instance>",
721
                    "Replaces all disks for the instance"),
722
  'modify': (SetInstanceParms, ARGS_ONE,
723
             [DEBUG_OPT, FORCE_OPT,
724
              cli_option("-m", "--memory", dest="mem",
725
                         help="Memory size",
726
                         default=None, type="unit", metavar="<mem>"),
727
              make_option("-p", "--cpu", dest="vcpus",
728
                          help="Number of virtual CPUs",
729
                          default=None, type="int", metavar="<PROC>"),
730
              make_option("-i", "--ip", dest="ip",
731
                          help="IP address ('none' or numeric IP)",
732
                          default=None, type="string", metavar="<ADDRESS>"),
733
              make_option("-b", "--bridge", dest="bridge",
734
                          help="Bridge to connect this instance to",
735
                          default=None, type="string", metavar="<bridge>"),
736
              ],
737
             "<instance>", "Alters the parameters of an instance"),
738
  'shutdown': (ShutdownInstance, ARGS_ANY,
739
               [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
740
                m_clust_opt, m_inst_opt, m_force_multi],
741
               "<instance>", "Stops an instance"),
742
  'startup': (StartupInstance, ARGS_ANY,
743
              [DEBUG_OPT, FORCE_OPT, m_force_multi,
744
               make_option("-e", "--extra", dest="extra_args",
745
                           help="Extra arguments for the instance's kernel",
746
                           default=None, type="string", metavar="<PARAMS>"),
747
               m_node_opt, m_pri_node_opt, m_sec_node_opt,
748
               m_clust_opt, m_inst_opt,
749
               ],
750
            "<instance>", "Starts an instance"),
751
  'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
752
                     "<instance>",
753
                     "Activate an instance's disks"),
754
  'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
755
                       "<instance>",
756
                       "Deactivate an instance's disks"),
757
  'list-tags': (ListTags, ARGS_ONE, [DEBUG_OPT],
758
                "<node_name>", "List the tags of the given instance"),
759
  'add-tags': (AddTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
760
               "<node_name> tag...", "Add tags to the given instance"),
761
  'remove-tags': (RemoveTags, ARGS_ATLEAST(1), [DEBUG_OPT, TAG_SRC_OPT],
762
                  "<node_name> tag...", "Remove tags from given instance"),
763
  }
764

    
765
if __name__ == '__main__':
766
  sys.exit(GenericMain(commands,
767
                       override={"tag_type": constants.TAG_INSTANCE}))