Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ f55ff7ec

History | View | Annotate | Download (26.9 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
                                ignore_failures=opts.ignore_failures)
275
  SubmitOpCode(op)
276
  return 0
277

    
278

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

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

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

    
292
  return 0
293

    
294

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

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

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

    
311

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

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

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

    
324

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

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

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

    
349

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

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

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

    
372

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

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

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

    
387

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

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

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

    
402

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

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

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

    
418

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

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

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

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

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

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

    
447

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

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

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

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

    
469

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

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

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

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

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

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

    
521

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

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

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

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

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

    
557
  logger.ToStdout(buf.getvalue().rstrip('\n'))
558
  return retcode
559

    
560

    
561
def SetInstanceParms(opts, args):
562
  """Modifies an instance.
563

    
564
  All parameters take effect only at the next restart of the instance.
565

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

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

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

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

    
591

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

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

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

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

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

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

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

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

    
625

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

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

    
774
if __name__ == '__main__':
775
  sys.exit(GenericMain(commands,
776
                       override={"tag_type": constants.TAG_INSTANCE}))