Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ 47988778

History | View | Annotate | Download (24.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 ListInstances(opts, args):
103
  """List nodes and their properties.
104

    
105
  """
106
  if opts.output is None:
107
    selected_fields = ["name", "os", "pnode", "admin_state",
108
                       "oper_state", "oper_ram"]
109
  else:
110
    selected_fields = opts.output.split(",")
111

    
112
  op = opcodes.OpQueryInstances(output_fields=selected_fields, names=[])
113
  output = SubmitOpCode(op)
114

    
115
  if not opts.no_headers:
116
    headers = {"name": "Instance", "os": "OS", "pnode": "Primary_node",
117
               "snodes": "Secondary_Nodes", "admin_state": "Autostart",
118
               "oper_state": "Status", "admin_ram": "Configured_memory",
119
               "oper_ram": "Memory", "disk_template": "Disk_template",
120
               "ip": "IP Address", "mac": "MAC Address",
121
               "bridge": "Bridge",
122
               "sda_size": "Disk/0", "sdb_size": "Disk/1"}
123
  else:
124
    headers = None
125

    
126
  if opts.human_readable:
127
    unitfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
128
  else:
129
    unitfields = None
130

    
131
  numfields = ["admin_ram", "oper_ram", "sda_size", "sdb_size"]
132

    
133
  # change raw values to nicer strings
134
  for row in output:
135
    for idx, field in enumerate(selected_fields):
136
      val = row[idx]
137
      if field == "snodes":
138
        val = ",".join(val) or "-"
139
      elif field == "admin_state":
140
        if val:
141
          val = "yes"
142
        else:
143
          val = "no"
144
      elif field == "oper_state":
145
        if val is None:
146
          val = "(node down)"
147
        elif val: # True
148
          val = "running"
149
        else:
150
          val = "stopped"
151
      elif field == "oper_ram":
152
        if val is None:
153
          val = "(node down)"
154
      elif field == "sda_size" or field == "sdb_size":
155
        if val is None:
156
          val = "N/A"
157
      row[idx] = str(val)
158

    
159
  data = GenerateTable(separator=opts.separator, headers=headers,
160
                       fields=selected_fields, unitfields=unitfields,
161
                       numfields=numfields, data=output)
162

    
163
  for line in data:
164
    logger.ToStdout(line)
165

    
166
  return 0
167

    
168

    
169
def AddInstance(opts, args):
170
  """Add an instance to the cluster.
171

    
172
  Args:
173
    opts - class with options as members
174
    args - list with a single element, the instance name
175
  Opts used:
176
    mem - amount of memory to allocate to instance (MiB)
177
    size - amount of disk space to allocate to instance (MiB)
178
    os - which OS to run on instance
179
    node - node to run new instance on
180

    
181
  """
182
  instance = args[0]
183

    
184
  op = opcodes.OpCreateInstance(instance_name=instance, mem_size=opts.mem,
185
                                disk_size=opts.size, swap_size=opts.swap,
186
                                disk_template=opts.disk_template,
187
                                mode=constants.INSTANCE_CREATE,
188
                                os_type=opts.os, pnode=opts.node,
189
                                snode=opts.snode, vcpus=opts.vcpus,
190
                                ip=opts.ip, bridge=opts.bridge,
191
                                start=opts.start, ip_check=opts.ip_check,
192
                                wait_for_sync=opts.wait_for_sync)
193
  SubmitOpCode(op)
194
  return 0
195

    
196

    
197
def ReinstallInstance(opts, args):
198
  """Reinstall an instance.
199

    
200
  Args:
201
    opts - class with options as members
202
    args - list containing a single element, the instance name
203

    
204
  """
205
  instance_name = args[0]
206

    
207
  if not opts.force:
208
    usertext = ("This will reinstall the instance %s and remove "
209
                "all data. Continue?") % instance_name
210
    if not AskUser(usertext):
211
      return 1
212

    
213
  op = opcodes.OpReinstallInstance(instance_name=instance_name,
214
                                   os_type=opts.os)
215
  SubmitOpCode(op)
216

    
217
  return 0
218

    
219

    
220
def RemoveInstance(opts, args):
221
  """Remove an instance.
222

    
223
  Args:
224
    opts - class with options as members
225
    args - list containing a single element, the instance name
226

    
227
  """
228
  instance_name = args[0]
229
  force = opts.force
230

    
231
  if not force:
232
    usertext = ("This will remove the volumes of the instance %s"
233
                " (including mirrors), thus removing all the data"
234
                " of the instance. Continue?") % instance_name
235
    if not AskUser(usertext):
236
      return 1
237

    
238
  op = opcodes.OpRemoveInstance(instance_name=instance_name)
239
  SubmitOpCode(op)
240
  return 0
241

    
242

    
243
def RenameInstance(opts, args):
244
  """Rename an instance.
245

    
246
  Args:
247
    opts - class with options as members
248
    args - list containing two elements, the instance name and the new name
249

    
250
  """
251
  op = opcodes.OpRenameInstance(instance_name=args[0],
252
                                new_name=args[1],
253
                                ignore_ip=opts.ignore_ip)
254
  SubmitOpCode(op)
255

    
256
  return 0
257

    
258

    
259
def ActivateDisks(opts, args):
260
  """Activate an instance's disks.
261

    
262
  This serves two purposes:
263
    - it allows one (as long as the instance is not running) to mount
264
    the disks and modify them from the node
265
    - it repairs inactive secondary drbds
266

    
267
  """
268
  instance_name = args[0]
269
  op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
270
  disks_info = SubmitOpCode(op)
271
  for host, iname, nname in disks_info:
272
    print "%s:%s:%s" % (host, iname, nname)
273
  return 0
274

    
275

    
276
def DeactivateDisks(opts, args):
277
  """Command-line interface for _ShutdownInstanceBlockDevices.
278

    
279
  This function takes the instance name, looks for its primary node
280
  and the tries to shutdown its block devices on that node.
281

    
282
  """
283
  instance_name = args[0]
284
  op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
285
  SubmitOpCode(op)
286
  return 0
287

    
288

    
289
def StartupInstance(opts, args):
290
  """Startup an instance.
291

    
292
  Args:
293
    opts - class with options as members
294
    args - list containing a single element, the instance name
295

    
296
  """
297
  if opts.multi_mode is None:
298
    opts.multi_mode = _SHUTDOWN_INSTANCES
299
  inames = _ExpandMultiNames(opts.multi_mode, args)
300
  multi_on = len(inames) > 1
301
  for name in inames:
302
    op = opcodes.OpStartupInstance(instance_name=name,
303
                                   force=opts.force,
304
                                   extra_args=opts.extra_args)
305
    if multi_on:
306
      logger.ToStdout("Starting up %s" % name)
307
    SubmitOpCode(op)
308
  return 0
309

    
310

    
311
def ShutdownInstance(opts, args):
312
  """Shutdown an instance.
313

    
314
  Args:
315
    opts - class with options as members
316
    args - list containing a single element, the instance name
317

    
318
  """
319
  if opts.multi_mode is None:
320
    opts.multi_mode = _SHUTDOWN_INSTANCES
321
  inames = _ExpandMultiNames(opts.multi_mode, args)
322
  multi_on = len(inames) > 1
323
  for name in inames:
324
    op = opcodes.OpShutdownInstance(instance_name=name)
325
    if multi_on:
326
      logger.ToStdout("Shutting down %s" % name)
327
    SubmitOpCode(op)
328
  return 0
329

    
330

    
331
def AddMDDRBDComponent(opts, args):
332
  """Add a new component to a remote_raid1 disk.
333

    
334
  Args:
335
    opts - class with options as members
336
    args - list with a single element, the instance name
337

    
338
  """
339
  op = opcodes.OpAddMDDRBDComponent(instance_name=args[0],
340
                                    disk_name=opts.disk,
341
                                    remote_node=opts.node)
342
  SubmitOpCode(op)
343
  return 0
344

    
345

    
346
def RemoveMDDRBDComponent(opts, args):
347
  """Remove a component from a remote_raid1 disk.
348

    
349
  Args:
350
    opts - class with options as members
351
    args - list with a single element, the instance name
352

    
353
  """
354
  op = opcodes.OpRemoveMDDRBDComponent(instance_name=args[0],
355
                                       disk_name=opts.disk,
356
                                       disk_id=opts.port)
357
  SubmitOpCode(op)
358
  return 0
359

    
360

    
361
def ReplaceDisks(opts, args):
362
  """Replace the disks of an instance
363

    
364
  Args:
365
    opts - class with options as members
366
    args - list with a single element, the instance name
367

    
368
  """
369
  instance_name = args[0]
370
  new_secondary = opts.new_secondary
371
  op = opcodes.OpReplaceDisks(instance_name=args[0],
372
                              remote_node=opts.new_secondary)
373
  SubmitOpCode(op)
374
  return 0
375

    
376

    
377
def FailoverInstance(opts, args):
378
  """Failover an instance.
379

    
380
  The failover is done by shutting it down on its present node and
381
  starting it on the secondary.
382

    
383
  Args:
384
    opts - class with options as members
385
    args - list with a single element, the instance name
386
  Opts used:
387
    force - whether to failover without asking questions.
388

    
389
  """
390
  instance_name = args[0]
391
  force = opts.force
392

    
393
  if not force:
394
    usertext = ("Failover will happen to image %s."
395
                " This requires a shutdown of the instance. Continue?" %
396
                (instance_name,))
397
    if not AskUser(usertext):
398
      return 1
399

    
400
  op = opcodes.OpFailoverInstance(instance_name=instance_name,
401
                                  ignore_consistency=opts.ignore_consistency)
402
  SubmitOpCode(op)
403
  return 0
404

    
405

    
406
def ConnectToInstanceConsole(opts, args):
407
  """Connect to the console of an instance.
408

    
409
  Args:
410
    opts - class with options as members
411
    args - list with a single element, the instance name
412

    
413
  """
414
  instance_name = args[0]
415

    
416
  op = opcodes.OpConnectConsole(instance_name=instance_name)
417
  cmd, argv = SubmitOpCode(op)
418
  # drop lock and exec so other commands can run while we have console
419
  utils.Unlock("cmd")
420
  try:
421
    os.execvp(cmd, argv)
422
  finally:
423
    sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
424
                     (cmd, " ".join(argv)))
425
    os._exit(1)
426

    
427

    
428
def _FormatBlockDevInfo(buf, dev, indent_level):
429
  """Show block device information.
430

    
431
  This is only used by ShowInstanceConfig(), but it's too big to be
432
  left for an inline definition.
433

    
434
  """
435
  def helper(buf, dtype, status):
436
    """Format one line for phsyical device status."""
437
    if not status:
438
      buf.write("not active\n")
439
    else:
440
      (path, major, minor, syncp, estt, degr) = status
441
      buf.write("%s (%d:%d)" % (path, major, minor))
442
      if dtype in ("md_raid1", "drbd"):
443
        if syncp is not None:
444
          sync_text = "*RECOVERING* %5.2f%%," % syncp
445
          if estt:
446
            sync_text += " ETA %ds" % estt
447
          else:
448
            sync_text += " ETA unknown"
449
        else:
450
          sync_text = "in sync"
451
        if degr:
452
          degr_text = "*DEGRADED*"
453
        else:
454
          degr_text = "ok"
455
        buf.write(" %s, status %s" % (sync_text, degr_text))
456
      buf.write("\n")
457

    
458
  if dev["iv_name"] is not None:
459
    data = "  - %s, " % dev["iv_name"]
460
  else:
461
    data = "  - "
462
  data += "type: %s" % dev["dev_type"]
463
  if dev["logical_id"] is not None:
464
    data += ", logical_id: %s" % (dev["logical_id"],)
465
  elif dev["physical_id"] is not None:
466
    data += ", physical_id: %s" % (dev["physical_id"],)
467
  buf.write("%*s%s\n" % (2*indent_level, "", data))
468
  buf.write("%*s    primary:   " % (2*indent_level, ""))
469
  helper(buf, dev["dev_type"], dev["pstatus"])
470

    
471
  if dev["sstatus"]:
472
    buf.write("%*s    secondary: " % (2*indent_level, ""))
473
    helper(buf, dev["dev_type"], dev["sstatus"])
474

    
475
  if dev["children"]:
476
    for child in dev["children"]:
477
      _FormatBlockDevInfo(buf, child, indent_level+1)
478

    
479

    
480
def ShowInstanceConfig(opts, args):
481
  """Compute instance run-time status.
482

    
483
  """
484
  retcode = 0
485
  op = opcodes.OpQueryInstanceData(instances=args)
486
  result = SubmitOpCode(op)
487

    
488
  if not result:
489
    logger.ToStdout("No instances.")
490
    return 1
491

    
492
  buf = StringIO()
493
  retcode = 0
494
  for instance_name in result:
495
    instance = result[instance_name]
496
    buf.write("Instance name: %s\n" % instance["name"])
497
    buf.write("State: configured to be %s, actual state is %s\n" %
498
              (instance["config_state"], instance["run_state"]))
499
    buf.write("  Nodes:\n")
500
    buf.write("    - primary: %s\n" % instance["pnode"])
501
    buf.write("    - secondaries: %s\n" % ", ".join(instance["snodes"]))
502
    buf.write("  Operating system: %s\n" % instance["os"])
503
    buf.write("  Hardware:\n")
504
    buf.write("    - memory: %dMiB\n" % instance["memory"])
505
    buf.write("    - NICs: %s\n" %
506
        ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
507
                   (mac, ip, bridge)
508
                     for mac, ip, bridge in instance["nics"]]))
509
    buf.write("  Block devices:\n")
510

    
511
    for device in instance["disks"]:
512
      _FormatBlockDevInfo(buf, device, 1)
513

    
514
  logger.ToStdout(buf.getvalue().rstrip('\n'))
515
  return retcode
516

    
517

    
518
def SetInstanceParms(opts, args):
519
  """Modifies an instance.
520

    
521
  All parameters take effect only at the next restart of the instance.
522

    
523
  Args:
524
    opts - class with options as members
525
    args - list with a single element, the instance name
526
  Opts used:
527
    memory - the new memory size
528
    vcpus - the new number of cpus
529

    
530
  """
531
  if not opts.mem and not opts.vcpus and not opts.ip and not opts.bridge:
532
    logger.ToStdout("Please give at least one of the parameters.")
533
    return 1
534

    
535
  op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
536
                                  vcpus=opts.vcpus, ip=opts.ip,
537
                                  bridge=opts.bridge)
538
  result = SubmitOpCode(op)
539

    
540
  if result:
541
    logger.ToStdout("Modified instance %s" % args[0])
542
    for param, data in result:
543
      logger.ToStdout(" - %-5s -> %s" % (param, data))
544
    logger.ToStdout("Please don't forget that these parameters take effect"
545
                    " only at the next start of the instance.")
546
  return 0
547

    
548

    
549
# options used in more than one cmd
550
node_opt = make_option("-n", "--node", dest="node", help="Target node",
551
                       metavar="<node>")
552

    
553
os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
554
                    metavar="<os>")
555

    
556
# multi-instance selection options
557
m_pri_node_opt = make_option("--primary", dest="multi_mode",
558
                             help="Filter by nodes (primary only)",
559
                             const=_SHUTDOWN_NODES_PRI, action="store_const")
560

    
561
m_sec_node_opt = make_option("--secondary", dest="multi_mode",
562
                             help="Filter by nodes (secondary only)",
563
                             const=_SHUTDOWN_NODES_SEC, action="store_const")
564

    
565
m_node_opt = make_option("--node", dest="multi_mode",
566
                         help="Filter by nodes (primary and secondary)",
567
                         const=_SHUTDOWN_NODES_BOTH, action="store_const")
568

    
569
m_clust_opt = make_option("--all", dest="multi_mode",
570
                          help="Select all instances in the cluster",
571
                          const=_SHUTDOWN_CLUSTER, action="store_const")
572

    
573
m_inst_opt = make_option("--instance", dest="multi_mode",
574
                         help="Filter by instance name [default]",
575
                         const=_SHUTDOWN_INSTANCES, action="store_const")
576

    
577

    
578
# this is defined separately due to readability only
579
add_opts = [
580
  DEBUG_OPT,
581
  node_opt,
582
  cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
583
             " a suffix is used",
584
             default=20 * 1024, type="unit", metavar="<size>"),
585
  cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
586
             " suffix is used",
587
             default=4 * 1024, type="unit", metavar="<size>"),
588
  os_opt,
589
  cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
590
              default=128, type="unit", metavar="<mem>"),
591
  make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
592
              default=1, type="int", metavar="<PROC>"),
593
  make_option("-t", "--disk-template", dest="disk_template",
594
              help="Custom disk setup (diskless, plain, local_raid1 or"
595
              " remote_raid1)", default=None, metavar="TEMPL"),
596
  make_option("-i", "--ip", dest="ip",
597
              help="IP address ('none' [default], 'auto', or specify address)",
598
              default='none', type="string", metavar="<ADDRESS>"),
599
  make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
600
              action="store_false", help="Don't wait for sync (DANGEROUS!)"),
601
  make_option("--secondary-node", dest="snode",
602
              help="Secondary node for remote_raid1 disk layout",
603
              metavar="<node>"),
604
  make_option("-b", "--bridge", dest="bridge",
605
              help="Bridge to connect this instance to",
606
              default=None, metavar="<bridge>"),
607
  make_option("--no-start", dest="start", default=True,
608
              action="store_false", help="Don't start the instance after"
609
              " creation"),
610
  make_option("--no-ip-check", dest="ip_check", default=True,
611
              action="store_false", help="Don't check that the instance's IP"
612
              " is alive (only valid with --no-start)"),
613
  ]
614

    
615
commands = {
616
  'add': (AddInstance, ARGS_ONE, add_opts,
617
          "[opts...] <name>",
618
          "Creates and adds a new instance to the cluster"),
619
  'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
620
                [DEBUG_OPT, node_opt,
621
                 make_option("-b", "--disk", dest="disk", metavar="sdX",
622
                             help=("The name of the instance disk for which to"
623
                                   " add the mirror"))],
624
                "-n node -b disk <instance>",
625
                "Creates a new mirror for the instance"),
626
  'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT],
627
              "<instance>",
628
              "Opens a console on the specified instance"),
629
  'failover': (FailoverInstance, ARGS_ONE,
630
               [DEBUG_OPT, FORCE_OPT,
631
                make_option("--ignore-consistency", dest="ignore_consistency",
632
                            action="store_true", default=False,
633
                            help="Ignore the consistency of the disks on"
634
                            " the secondary"),
635
                ],
636
               "[-f] <instance>",
637
               "Stops the instance and starts it on the backup node, using"
638
               " the remote mirror (only for instances of type remote_raid1)"),
639
  'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
640
           "Show information on the specified instance"),
641
  'list': (ListInstances, ARGS_NONE,
642
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
643
           "", "Lists the instances and their status"),
644
  'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
645
                "[-f] <instance>", "Reinstall the instance"),
646
  'remove': (RemoveInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT],
647
             "[-f] <instance>", "Shuts down the instance and removes it"),
648
  'remove-mirror': (RemoveMDDRBDComponent, ARGS_ONE,
649
                   [DEBUG_OPT, node_opt,
650
                    make_option("-b", "--disk", dest="disk", metavar="sdX",
651
                                help=("The name of the instance disk"
652
                                      " for which to add the mirror")),
653
                    make_option("-p", "--port", dest="port", metavar="PORT",
654
                                help=("The port of the drbd device"
655
                                      " which to remove from the mirror"),
656
                                type="int"),
657
                    ],
658
                   "-b disk -p port <instance>",
659
                   "Removes a mirror from the instance"),
660
  'rename': (RenameInstance, ARGS_FIXED(2),
661
             [DEBUG_OPT,
662
              make_option("--no-ip-check", dest="ignore_ip",
663
                          help="Do not check that the IP of the new name"
664
                          " is alive",
665
                          default=False, action="store_true"),
666
              ],
667
             "<instance> <new_name>", "Rename the instance"),
668
  'replace-disks': (ReplaceDisks, ARGS_ONE,
669
                    [DEBUG_OPT,
670
                     make_option("-n", "--new-secondary", dest="new_secondary",
671
                                 metavar="NODE",
672
                                 help=("New secondary node (if you want to"
673
                                       " change the secondary)"))],
674
                    "[-n NODE] <instance>",
675
                    "Replaces all disks for the instance"),
676
  'modify': (SetInstanceParms, ARGS_ONE,
677
             [DEBUG_OPT, FORCE_OPT,
678
              cli_option("-m", "--memory", dest="mem",
679
                         help="Memory size",
680
                         default=None, type="unit", metavar="<mem>"),
681
              make_option("-p", "--cpu", dest="vcpus",
682
                          help="Number of virtual CPUs",
683
                          default=None, type="int", metavar="<PROC>"),
684
              make_option("-i", "--ip", dest="ip",
685
                          help="IP address ('none' or numeric IP)",
686
                          default=None, type="string", metavar="<ADDRESS>"),
687
              make_option("-b", "--bridge", dest="bridge",
688
                          help="Bridge to connect this instance to",
689
                          default=None, type="string", metavar="<bridge>"),
690
              ],
691
             "<instance>", "Alters the parameters of an instance"),
692
  'shutdown': (ShutdownInstance, ARGS_ANY,
693
               [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
694
                m_clust_opt, m_inst_opt],
695
               "<instance>", "Stops an instance"),
696
  'startup': (StartupInstance, ARGS_ANY,
697
              [DEBUG_OPT, FORCE_OPT,
698
               make_option("-e", "--extra", dest="extra_args",
699
                           help="Extra arguments for the instance's kernel",
700
                           default=None, type="string", metavar="<PARAMS>"),
701
               m_node_opt, m_pri_node_opt, m_sec_node_opt,
702
               m_clust_opt, m_inst_opt,
703
               ],
704
            "<instance>", "Starts an instance"),
705
  'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
706
                     "<instance>",
707
                     "Activate an instance's disks"),
708
  'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
709
                       "<instance>",
710
                       "Deactivate an instance's disks"),
711
  }
712

    
713
if __name__ == '__main__':
714
  sys.exit(GenericMain(commands))