Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-instance @ 312ac745

History | View | Annotate | Download (23.2 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, start=True,
191
                                wait_for_sync=opts.wait_for_sync)
192
  SubmitOpCode(op)
193
  return 0
194

    
195

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

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

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

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

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

    
216
  return 0
217

    
218

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

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

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

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

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

    
241

    
242
def ActivateDisks(opts, args):
243
  """Activate an instance's disks.
244

    
245
  This serves two purposes:
246
    - it allows one (as long as the instance is not running) to mount
247
    the disks and modify them from the node
248
    - it repairs inactive secondary drbds
249

    
250
  """
251
  instance_name = args[0]
252
  op = opcodes.OpActivateInstanceDisks(instance_name=instance_name)
253
  disks_info = SubmitOpCode(op)
254
  for host, iname, nname in disks_info:
255
    print "%s:%s:%s" % (host, iname, nname)
256
  return 0
257

    
258

    
259
def DeactivateDisks(opts, args):
260
  """Command-line interface for _ShutdownInstanceBlockDevices.
261

    
262
  This function takes the instance name, looks for its primary node
263
  and the tries to shutdown its block devices on that node.
264

    
265
  """
266
  instance_name = args[0]
267
  op = opcodes.OpDeactivateInstanceDisks(instance_name=instance_name)
268
  SubmitOpCode(op)
269
  return 0
270

    
271

    
272
def StartupInstance(opts, args):
273
  """Shutdown an instance.
274

    
275
  Args:
276
    opts - class with options as members
277
    args - list containing a single element, the instance name
278

    
279
  """
280
  if opts.multi_mode is None:
281
    opts.multi_mode = _SHUTDOWN_INSTANCES
282
  inames = _ExpandMultiNames(opts.multi_mode, args)
283
  multi_on = len(inames) > 1
284
  for name in inames:
285
    op = opcodes.OpStartupInstance(instance_name=name,
286
                                   force=opts.force,
287
                                   extra_args=opts.extra_args)
288
    if multi_on:
289
      logger.ToStdout("Starting up %s" % name)
290
    SubmitOpCode(op)
291
  return 0
292

    
293

    
294
def ShutdownInstance(opts, args):
295
  """Shutdown an instance.
296

    
297
  Args:
298
    opts - class with options as members
299
    args - list containing a single element, the instance name
300

    
301
  """
302
  if opts.multi_mode is None:
303
    opts.multi_mode = _SHUTDOWN_INSTANCES
304
  inames = _ExpandMultiNames(opts.multi_mode, args)
305
  multi_on = len(inames) > 1
306
  for name in inames:
307
    op = opcodes.OpShutdownInstance(instance_name=name)
308
    if multi_on:
309
      logger.ToStdout("Shutting down %s" % name)
310
    SubmitOpCode(op)
311
  return 0
312

    
313

    
314
def AddMDDRBDComponent(opts, args):
315
  """Add a new component to a remote_raid1 disk.
316

    
317
  Args:
318
    opts - class with options as members
319
    args - list with a single element, the instance name
320

    
321
  """
322
  op = opcodes.OpAddMDDRBDComponent(instance_name=args[0],
323
                                    disk_name=opts.disk,
324
                                    remote_node=opts.node)
325
  SubmitOpCode(op)
326
  return 0
327

    
328

    
329
def RemoveMDDRBDComponent(opts, args):
330
  """Remove a component from a remote_raid1 disk.
331

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

    
336
  """
337
  op = opcodes.OpRemoveMDDRBDComponent(instance_name=args[0],
338
                                       disk_name=opts.disk,
339
                                       disk_id=opts.port)
340
  SubmitOpCode(op)
341
  return 0
342

    
343

    
344
def ReplaceDisks(opts, args):
345
  """Replace the disks of an instance
346

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

    
351
  """
352
  instance_name = args[0]
353
  new_secondary = opts.new_secondary
354
  op = opcodes.OpReplaceDisks(instance_name=args[0],
355
                              remote_node=opts.new_secondary)
356
  SubmitOpCode(op)
357
  return 0
358

    
359

    
360
def FailoverInstance(opts, args):
361
  """Failover an instance.
362

    
363
  The failover is done by shutting it down on its present node and
364
  starting it on the secondary.
365

    
366
  Args:
367
    opts - class with options as members
368
    args - list with a single element, the instance name
369
  Opts used:
370
    force - whether to failover without asking questions.
371

    
372
  """
373
  instance_name = args[0]
374
  force = opts.force
375

    
376
  if not force:
377
    usertext = ("Failover will happen to image %s."
378
                " This requires a shutdown of the instance. Continue?" %
379
                (instance_name,))
380
    if not opts._ask_user(usertext):
381
      return 1
382

    
383
  op = opcodes.OpFailoverInstance(instance_name=instance_name,
384
                                  ignore_consistency=opts.ignore_consistency)
385
  SubmitOpCode(op)
386
  return 0
387

    
388

    
389
def ConnectToInstanceConsole(opts, args):
390
  """Connect to the console of an instance.
391

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

    
396
  """
397
  instance_name = args[0]
398

    
399
  op = opcodes.OpConnectConsole(instance_name=instance_name)
400
  cmd, argv = SubmitOpCode(op)
401
  # drop lock and exec so other commands can run while we have console
402
  utils.Unlock("cmd")
403
  try:
404
    os.execvp(cmd, argv)
405
  finally:
406
    sys.stderr.write("Can't run console command %s with arguments:\n'%s'" %
407
                     (cmd, " ".join(argv)))
408
    os._exit(1)
409

    
410

    
411
def _FormatBlockDevInfo(buf, dev, indent_level):
412
  """Show block device information.
413

    
414
  This is only used by ShowInstanceConfig(), but it's too big to be
415
  left for an inline definition.
416

    
417
  """
418
  def helper(buf, dtype, status):
419
    """Format one line for phsyical device status."""
420
    if not status:
421
      buf.write("not active\n")
422
    else:
423
      (path, major, minor, syncp, estt, degr) = status
424
      buf.write("%s (%d:%d)" % (path, major, minor))
425
      if dtype in ("md_raid1", "drbd"):
426
        if syncp is not None:
427
          sync_text = "*RECOVERING* %5.2f%%," % syncp
428
          if estt:
429
            sync_text += " ETA %ds" % estt
430
          else:
431
            sync_text += " ETA unknown"
432
        else:
433
          sync_text = "in sync"
434
        if degr:
435
          degr_text = "*DEGRADED*"
436
        else:
437
          degr_text = "ok"
438
        buf.write(" %s, status %s" % (sync_text, degr_text))
439
      buf.write("\n")
440

    
441
  if dev["iv_name"] is not None:
442
    data = "  - %s, " % dev["iv_name"]
443
  else:
444
    data = "  - "
445
  data += "type: %s" % dev["dev_type"]
446
  if dev["logical_id"] is not None:
447
    data += ", logical_id: %s" % (dev["logical_id"],)
448
  elif dev["physical_id"] is not None:
449
    data += ", physical_id: %s" % (dev["physical_id"],)
450
  buf.write("%*s%s\n" % (2*indent_level, "", data))
451
  buf.write("%*s    primary:   " % (2*indent_level, ""))
452
  helper(buf, dev["dev_type"], dev["pstatus"])
453

    
454
  if dev["sstatus"]:
455
    buf.write("%*s    secondary: " % (2*indent_level, ""))
456
    helper(buf, dev["dev_type"], dev["sstatus"])
457

    
458
  if dev["children"]:
459
    for child in dev["children"]:
460
      _FormatBlockDevInfo(buf, child, indent_level+1)
461

    
462

    
463
def ShowInstanceConfig(opts, args):
464
  """Compute instance run-time status.
465

    
466
  """
467
  retcode = 0
468
  op = opcodes.OpQueryInstanceData(instances=args)
469
  result = SubmitOpCode(op)
470

    
471
  if not result:
472
    logger.ToStdout("No instances.")
473
    return 1
474

    
475
  buf = StringIO()
476
  retcode = 0
477
  for instance_name in result:
478
    instance = result[instance_name]
479
    buf.write("Instance name: %s\n" % instance["name"])
480
    buf.write("State: configured to be %s, actual state is %s\n" %
481
              (instance["config_state"], instance["run_state"]))
482
    buf.write("  Nodes:\n")
483
    buf.write("    - primary: %s\n" % instance["pnode"])
484
    buf.write("    - secondaries: %s\n" % ", ".join(instance["snodes"]))
485
    buf.write("  Operating system: %s\n" % instance["os"])
486
    buf.write("  Hardware:\n")
487
    buf.write("    - memory: %dMiB\n" % instance["memory"])
488
    buf.write("    - NICs: %s\n" %
489
        ", ".join(["{MAC: %s, IP: %s, bridge: %s}" %
490
                   (mac, ip, bridge)
491
                     for mac, ip, bridge in instance["nics"]]))
492
    buf.write("  Block devices:\n")
493

    
494
    for device in instance["disks"]:
495
      _FormatBlockDevInfo(buf, device, 1)
496

    
497
  logger.ToStdout(buf.getvalue().rstrip('\n'))
498
  return retcode
499

    
500

    
501
def SetInstanceParms(opts, args):
502
  """Modifies an instance.
503

    
504
  All parameters take effect only at the next restart of the instance.
505

    
506
  Args:
507
    opts - class with options as members
508
    args - list with a single element, the instance name
509
  Opts used:
510
    memory - the new memory size
511
    vcpus - the new number of cpus
512

    
513
  """
514
  if not opts.mem and not opts.vcpus and not opts.ip and not opts.bridge:
515
    logger.ToStdout("Please give at least one of the parameters.")
516
    return 1
517

    
518
  op = opcodes.OpSetInstanceParms(instance_name=args[0], mem=opts.mem,
519
                                  vcpus=opts.vcpus, ip=opts.ip,
520
                                  bridge=opts.bridge)
521
  result = SubmitOpCode(op)
522

    
523
  if result:
524
    logger.ToStdout("Modified instance %s" % args[0])
525
    for param, data in result:
526
      logger.ToStdout(" - %-5s -> %s" % (param, data))
527
    logger.ToStdout("Please don't forget that these parameters take effect"
528
                    " only at the next start of the instance.")
529
  return 0
530

    
531

    
532
# options used in more than one cmd
533
node_opt = make_option("-n", "--node", dest="node", help="Target node",
534
                       metavar="<node>")
535

    
536
os_opt = cli_option("-o", "--os-type", dest="os", help="What OS to run",
537
                    metavar="<os>")
538

    
539
# multi-instance selection options
540
m_pri_node_opt = make_option("--primary", dest="multi_mode",
541
                             help="Filter by nodes (primary only)",
542
                             const=_SHUTDOWN_NODES_PRI, action="store_const")
543

    
544
m_sec_node_opt = make_option("--secondary", dest="multi_mode",
545
                             help="Filter by nodes (secondary only)",
546
                             const=_SHUTDOWN_NODES_SEC, action="store_const")
547

    
548
m_node_opt = make_option("--node", dest="multi_mode",
549
                         help="Filter by nodes (primary and secondary)",
550
                         const=_SHUTDOWN_NODES_BOTH, action="store_const")
551

    
552
m_clust_opt = make_option("--all", dest="multi_mode",
553
                          help="Select all instances in the cluster",
554
                          const=_SHUTDOWN_CLUSTER, action="store_const")
555

    
556
m_inst_opt = make_option("--instance", dest="multi_mode",
557
                         help="Filter by instance name [default]",
558
                         const=_SHUTDOWN_INSTANCES, action="store_const")
559

    
560

    
561
# this is defined separately due to readability only
562
add_opts = [
563
  DEBUG_OPT,
564
  node_opt,
565
  cli_option("-s", "--os-size", dest="size", help="Disk size, in MiB unless"
566
             " a suffix is used",
567
             default=20 * 1024, type="unit", metavar="<size>"),
568
  cli_option("--swap-size", dest="swap", help="Swap size, in MiB unless a"
569
             " suffix is used",
570
             default=4 * 1024, type="unit", metavar="<size>"),
571
  os_opt,
572
  cli_option("-m", "--memory", dest="mem", help="Memory size (in MiB)",
573
              default=128, type="unit", metavar="<mem>"),
574
  make_option("-p", "--cpu", dest="vcpus", help="Number of virtual CPUs",
575
              default=1, type="int", metavar="<PROC>"),
576
  make_option("-t", "--disk-template", dest="disk_template",
577
              help="Custom disk setup (diskless, plain, local_raid1 or"
578
              " remote_raid1)", default=None, metavar="TEMPL"),
579
  make_option("-i", "--ip", dest="ip",
580
              help="IP address ('none' [default], 'auto', or specify address)",
581
              default='none', type="string", metavar="<ADDRESS>"),
582
  make_option("--no-wait-for-sync", dest="wait_for_sync", default=True,
583
              action="store_false", help="Don't wait for sync (DANGEROUS!)"),
584
  make_option("--secondary-node", dest="snode",
585
              help="Secondary node for remote_raid1 disk layout",
586
              metavar="<node>"),
587
  make_option("-b", "--bridge", dest="bridge",
588
              help="Bridge to connect this instance to",
589
              default=None, metavar="<bridge>")
590
  ]
591

    
592
commands = {
593
  'add': (AddInstance, ARGS_ONE, add_opts,
594
          "[opts...] <name>",
595
          "Creates and adds a new instance to the cluster"),
596
  'add-mirror': (AddMDDRBDComponent, ARGS_ONE,
597
                [DEBUG_OPT, node_opt,
598
                 make_option("-b", "--disk", dest="disk", metavar="sdX",
599
                             help=("The name of the instance disk for which to"
600
                                   " add the mirror"))],
601
                "-n node -b disk <instance>",
602
                "Creates a new mirror for the instance"),
603
  'console': (ConnectToInstanceConsole, ARGS_ONE, [DEBUG_OPT],
604
              "<instance>",
605
              "Opens a console on the specified instance"),
606
  'failover': (FailoverInstance, ARGS_ONE,
607
               [DEBUG_OPT, FORCE_OPT,
608
                make_option("--ignore-consistency", dest="ignore_consistency",
609
                            action="store_true", default=False,
610
                            help="Ignore the consistency of the disks on"
611
                            " the secondary"),
612
                ],
613
               "[-f] <instance>",
614
               "Stops the instance and starts it on the backup node, using"
615
               " the remote mirror (only for instances of type remote_raid1)"),
616
  'info': (ShowInstanceConfig, ARGS_ANY, [DEBUG_OPT], "[<instance>...]",
617
           "Show information on the specified instance"),
618
  'list': (ListInstances, ARGS_NONE,
619
           [DEBUG_OPT, NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
620
           "", "Lists the instances and their status"),
621
  'reinstall': (ReinstallInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT, os_opt],
622
                "[-f] <instance>", "Reinstall the instance"),
623
  'remove': (RemoveInstance, ARGS_ONE, [DEBUG_OPT, FORCE_OPT],
624
             "[-f] <instance>", "Shuts down the instance and removes it"),
625
  'remove-mirror': (RemoveMDDRBDComponent, ARGS_ONE,
626
                   [DEBUG_OPT, node_opt,
627
                    make_option("-b", "--disk", dest="disk", metavar="sdX",
628
                                help=("The name of the instance disk"
629
                                      " for which to add the mirror")),
630
                    make_option("-p", "--port", dest="port", metavar="PORT",
631
                                help=("The port of the drbd device"
632
                                      " which to remove from the mirror"),
633
                                type="int"),
634
                    ],
635
                   "-b disk -p port <instance>",
636
                   "Removes a mirror from the instance"),
637
  'replace-disks': (ReplaceDisks, ARGS_ONE,
638
                    [DEBUG_OPT,
639
                     make_option("-n", "--new-secondary", dest="new_secondary",
640
                                 metavar="NODE",
641
                                 help=("New secondary node (if you want to"
642
                                       " change the secondary)"))],
643
                    "[-n NODE] <instance>",
644
                    "Replaces all disks for the instance"),
645
  'modify': (SetInstanceParms, ARGS_ONE,
646
             [DEBUG_OPT, FORCE_OPT,
647
              cli_option("-m", "--memory", dest="mem",
648
                         help="Memory size",
649
                         default=None, type="unit", metavar="<mem>"),
650
              make_option("-p", "--cpu", dest="vcpus",
651
                          help="Number of virtual CPUs",
652
                          default=None, type="int", metavar="<PROC>"),
653
              make_option("-i", "--ip", dest="ip",
654
                          help="IP address ('none' or numeric IP)",
655
                          default=None, type="string", metavar="<ADDRESS>"),
656
              make_option("-b", "--bridge", dest="bridge",
657
                          help="Bridge to connect this instance to",
658
                          default=None, type="string", metavar="<bridge>")
659
              ],
660
             "<instance>", "Alters the parameters of an instance"),
661
  'shutdown': (ShutdownInstance, ARGS_ANY,
662
               [DEBUG_OPT, m_node_opt, m_pri_node_opt, m_sec_node_opt,
663
                m_clust_opt, m_inst_opt],
664
               "<instance>", "Stops an instance"),
665
  'startup': (StartupInstance, ARGS_ANY,
666
              [DEBUG_OPT, FORCE_OPT,
667
               make_option("-e", "--extra", dest="extra_args",
668
                           help="Extra arguments for the instance's kernel",
669
                           default=None, type="string", metavar="<PARAMS>"),
670
               m_node_opt, m_pri_node_opt, m_sec_node_opt,
671
               m_clust_opt, m_inst_opt,
672
               ],
673
            "<instance>", "Starts an instance"),
674
  'activate-disks': (ActivateDisks, ARGS_ONE, [DEBUG_OPT],
675
                     "<instance>",
676
                     "Activate an instance's disks"),
677
  'deactivate-disks': (DeactivateDisks, ARGS_ONE, [DEBUG_OPT],
678
                       "<instance>",
679
                       "Deactivate an instance's disks"),
680
  }
681

    
682
if __name__ == '__main__':
683
  sys.exit(GenericMain(commands))