gnt-cluster 23.2 KB
Newer Older
Iustin Pop's avatar
Iustin Pop committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/python
#

# Copyright (C) 2006, 2007 Google Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.


22
23
24
25
# pylint: disable-msg=W0401,W0614
# W0401: Wildcard import ganeti.cli
# W0614: Unused import %s from wildcard import (since we need cli)

Iustin Pop's avatar
Iustin Pop committed
26
import sys
27
import os.path
28
import time
Iustin Pop's avatar
Iustin Pop committed
29
30
31

from ganeti.cli import *
from ganeti import opcodes
32
from ganeti import constants
33
from ganeti import errors
34
from ganeti import utils
35
from ganeti import bootstrap
36
from ganeti import ssh
37
from ganeti import objects
Iustin Pop's avatar
Iustin Pop committed
38
39


40
@UsesRPC
Iustin Pop's avatar
Iustin Pop committed
41
42
43
def InitCluster(opts, args):
  """Initialize the cluster.

44
45
46
47
48
49
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain only one element, the desired
      cluster name
  @rtype: int
  @return: the desired exit code
Iustin Pop's avatar
Iustin Pop committed
50
51

  """
52
  if not opts.lvm_storage and opts.vg_name:
53
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
54
55
56
57
58
59
    return 1

  vg_name = opts.vg_name
  if opts.lvm_storage and not opts.vg_name:
    vg_name = constants.DEFAULT_VG

60
  hvlist = opts.enabled_hypervisors
61
62
  if hvlist is None:
    hvlist = constants.DEFAULT_ENABLED_HYPERVISOR
63
  hvlist = hvlist.split(",")
64

65
  hvparams = dict(opts.hvparams)
66
  beparams = opts.beparams
67
  nicparams = opts.nicparams
68
69

  # prepare beparams dict
70
  beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams)
71
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
72

73
74
75
76
  # prepare nicparams dict
  nicparams = objects.FillDict(constants.NICC_DEFAULTS, nicparams)
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)

77
78
79
80
  # prepare hvparams dict
  for hv in constants.HYPER_TYPES:
    if hv not in hvparams:
      hvparams[hv] = {}
81
    hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv])
82
    utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES)
83

84
85
86
87
88
  bootstrap.InitCluster(cluster_name=args[0],
                        secondary_ip=opts.secondary_ip,
                        vg_name=vg_name,
                        mac_prefix=opts.mac_prefix,
                        master_netdev=opts.master_netdev,
89
90
91
                        file_storage_dir=opts.file_storage_dir,
                        enabled_hypervisors=hvlist,
                        hvparams=hvparams,
92
                        beparams=beparams,
93
                        nicparams=nicparams,
94
                        candidate_pool_size=opts.candidate_pool_size,
95
                        modify_etc_hosts=opts.modify_etc_hosts,
96
                        )
97
98
  op = opcodes.OpPostInitCluster()
  SubmitOpCode(op)
Iustin Pop's avatar
Iustin Pop committed
99
100
101
  return 0


102
@UsesRPC
Iustin Pop's avatar
Iustin Pop committed
103
104
105
def DestroyCluster(opts, args):
  """Destroy the cluster.

106
107
108
109
110
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code
111

Iustin Pop's avatar
Iustin Pop committed
112
113
  """
  if not opts.yes_do_it:
114
115
    ToStderr("Destroying a cluster is irreversible. If you really want"
             " destroy this cluster, supply the --yes-do-it option.")
Iustin Pop's avatar
Iustin Pop committed
116
117
118
    return 1

  op = opcodes.OpDestroyCluster()
Iustin Pop's avatar
Iustin Pop committed
119
120
121
122
  master = SubmitOpCode(op)
  # if we reached this, the opcode didn't fail; we can proceed to
  # shutdown all the daemons
  bootstrap.FinalizeClusterDestroy(master)
Iustin Pop's avatar
Iustin Pop committed
123
124
125
  return 0


126
127
128
def RenameCluster(opts, args):
  """Rename the cluster.

129
130
131
132
133
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain only one element, the new cluster name
  @rtype: int
  @return: the desired exit code
134
135
136
137
138
139
140
141

  """
  name = args[0]
  if not opts.force:
    usertext = ("This will rename the cluster to '%s'. If you are connected"
                " over the network to the cluster name, the operation is very"
                " dangerous as the IP address will be removed from the node"
                " and the change may not go through. Continue?") % name
142
    if not AskUser(usertext):
143
144
145
146
147
148
149
      return 1

  op = opcodes.OpRenameCluster(name=name)
  SubmitOpCode(op)
  return 0


150
151
152
153
154
155
156
157
158
159
def RedistributeConfig(opts, args):
  """Forces push of the cluster configuration.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: empty list
  @rtype: int
  @return: the desired exit code

  """
160
  op = opcodes.OpRedistributeConfig()
161
162
163
164
  SubmitOrSend(op, opts)
  return 0


Iustin Pop's avatar
Iustin Pop committed
165
166
167
def ShowClusterVersion(opts, args):
  """Write version of ganeti software to the standard output.

168
169
170
171
172
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code
Iustin Pop's avatar
Iustin Pop committed
173
174

  """
175
176
  cl = GetClient()
  result = cl.QueryClusterInfo()
177
178
179
180
181
  ToStdout("Software version: %s", result["software_version"])
  ToStdout("Internode protocol: %s", result["protocol_version"])
  ToStdout("Configuration format: %s", result["config_version"])
  ToStdout("OS api version: %s", result["os_api_version"])
  ToStdout("Export interface: %s", result["export_version"])
Iustin Pop's avatar
Iustin Pop committed
182
183
184
185
186
187
  return 0


def ShowClusterMaster(opts, args):
  """Write name of master node to the standard output.

188
189
190
191
192
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code
Iustin Pop's avatar
Iustin Pop committed
193
194

  """
195
196
  master = bootstrap.GetMaster()
  ToStdout(master)
Iustin Pop's avatar
Iustin Pop committed
197
198
  return 0

199
200
201
202
203
204
205
206
207
208
209
def _PrintGroupedParams(paramsdict):
  """Print Grouped parameters (be, nic, disk) by group.

  @type paramsdict: dict of dicts
  @param paramsdict: {group: {param: value, ...}, ...}

  """
  for gr_name, gr_dict in paramsdict.items():
    ToStdout("  - %s:", gr_name)
    for item, val in gr_dict.iteritems():
      ToStdout("      %s: %s", item, val)
Iustin Pop's avatar
Iustin Pop committed
210
211
212
213

def ShowClusterConfig(opts, args):
  """Shows cluster information.

214
215
216
217
218
219
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code

Iustin Pop's avatar
Iustin Pop committed
220
  """
221
222
  cl = GetClient()
  result = cl.QueryClusterInfo()
Iustin Pop's avatar
Iustin Pop committed
223

224
  ToStdout("Cluster name: %s", result["name"])
Iustin Pop's avatar
Iustin Pop committed
225

226
227
228
  ToStdout("Creation time: %s", utils.FormatTime(result["ctime"]))
  ToStdout("Modification time: %s", utils.FormatTime(result["mtime"]))

229
  ToStdout("Master node: %s", result["master"])
Iustin Pop's avatar
Iustin Pop committed
230

231
232
  ToStdout("Architecture (this node): %s (%s)",
           result["architecture"][0], result["architecture"][1])
Iustin Pop's avatar
Iustin Pop committed
233

234
235
236
237
238
239
240
  if result["tags"]:
    tags = ", ".join(utils.NiceSort(result["tags"]))
  else:
    tags = "(none)"

  ToStdout("Tags: %s", tags)

241
  ToStdout("Default hypervisor: %s", result["default_hypervisor"])
242
  ToStdout("Enabled hypervisors: %s", ", ".join(result["enabled_hypervisors"]))
243

244
  ToStdout("Hypervisor parameters:")
245
  _PrintGroupedParams(result["hvparams"])
246

247
  ToStdout("Cluster parameters:")
248
  ToStdout("  - candidate pool size: %s", result["candidate_pool_size"])
249
250
251
  ToStdout("  - master netdev: %s", result["master_netdev"])
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
252
253

  ToStdout("Default instance parameters:")
254
255
256
257
  _PrintGroupedParams(result["beparams"])

  ToStdout("Default nic parameters:")
  _PrintGroupedParams(result["nicparams"])
258

Iustin Pop's avatar
Iustin Pop committed
259
260
261
262
263
264
  return 0


def ClusterCopyFile(opts, args):
  """Copy a file from master to some nodes.

265
266
267
268
269
270
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain only one element, the path of
      the file to be copied
  @rtype: int
  @return: the desired exit code
Iustin Pop's avatar
Iustin Pop committed
271
272

  """
273
274
275
276
  filename = args[0]
  if not os.path.exists(filename):
    raise errors.OpPrereqError("No such filename '%s'" % filename)

Iustin Pop's avatar
Iustin Pop committed
277
278
  cl = GetClient()

279
280
  myname = utils.HostInfo().name

Iustin Pop's avatar
Iustin Pop committed
281
282
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]

283
284
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl)
  results = [name for name in results if name != myname]
Michael Hanselmann's avatar
Michael Hanselmann committed
285

Iustin Pop's avatar
Iustin Pop committed
286
  srun = ssh.SshRunner(cluster_name=cluster_name)
287
288
  for node in results:
    if not srun.CopyFileToNode(node, filename):
289
      ToStderr("Copy of file %s to node %s failed", filename, node)
290

Iustin Pop's avatar
Iustin Pop committed
291
292
293
294
295
296
  return 0


def RunClusterCommand(opts, args):
  """Run a command on some nodes.

297
298
299
300
301
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain the command to be run and its arguments
  @rtype: int
  @return: the desired exit code
Iustin Pop's avatar
Iustin Pop committed
302
303

  """
Iustin Pop's avatar
Iustin Pop committed
304
  cl = GetClient()
Michael Hanselmann's avatar
Michael Hanselmann committed
305

Iustin Pop's avatar
Iustin Pop committed
306
  command = " ".join(args)
307
308

  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl)
Iustin Pop's avatar
Iustin Pop committed
309
310
311

  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
                                                    "master_node"])
312

Iustin Pop's avatar
Iustin Pop committed
313
  srun = ssh.SshRunner(cluster_name=cluster_name)
314

Michael Hanselmann's avatar
Michael Hanselmann committed
315
  # Make sure master node is at list end
316
317
318
319
320
321
  if master_node in nodes:
    nodes.remove(master_node)
    nodes.append(master_node)

  for name in nodes:
    result = srun.Run(name, "root", command)
322
323
324
325
    ToStdout("------------------------------------------------")
    ToStdout("node: %s", name)
    ToStdout("%s", result.output)
    ToStdout("return code = %s", result.exit_code)
326
327

  return 0
Iustin Pop's avatar
Iustin Pop committed
328
329
330
331
332


def VerifyCluster(opts, args):
  """Verify integrity of cluster, performing various test on nodes.

333
334
335
336
337
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code
Iustin Pop's avatar
Iustin Pop committed
338
339

  """
Iustin Pop's avatar
Iustin Pop committed
340
  skip_checks = []
341
342
  if opts.skip_nplusone_mem:
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
343
344
  op = opcodes.OpVerifyCluster(skip_checks=skip_checks,
                               verbose=opts.verbose,
345
346
                               error_codes=opts.error_codes,
                               debug_simulate_errors=opts.simulate_errors)
347
348
349
350
  if SubmitOpCode(op):
    return 0
  else:
    return 1
Iustin Pop's avatar
Iustin Pop committed
351
352


353
354
355
def VerifyDisks(opts, args):
  """Verify integrity of cluster disks.

356
357
358
359
360
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code
361
362
363
364

  """
  op = opcodes.OpVerifyDisks()
  result = SubmitOpCode(op)
365
  if not isinstance(result, (list, tuple)) or len(result) != 3:
366
367
    raise errors.ProgrammerError("Unknown result type for OpVerifyDisks")

368
  bad_nodes, instances, missing = result
369

370
  retcode = constants.EXIT_SUCCESS
371

372
373
374
  if bad_nodes:
    for node, text in bad_nodes.items():
      ToStdout("Error gathering data on node %s: %s",
375
               node, utils.SafeEncode(text[-400:]))
376
      retcode |= 1
377
      ToStdout("You need to fix these nodes first before fixing instances")
378

379
380
  if instances:
    for iname in instances:
381
382
      if iname in missing:
        continue
383
384
      op = opcodes.OpActivateInstanceDisks(instance_name=iname)
      try:
385
        ToStdout("Activating disks for instance '%s'", iname)
386
387
388
389
        SubmitOpCode(op)
      except errors.GenericError, err:
        nret, msg = FormatError(err)
        retcode |= nret
390
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
391
392
393

  if missing:
    for iname, ival in missing.iteritems():
394
      all_missing = utils.all(ival, lambda x: x[0] in bad_nodes)
395
      if all_missing:
396
397
        ToStdout("Instance %s cannot be verified as it lives on"
                 " broken nodes", iname)
398
      else:
399
        ToStdout("Instance %s has missing logical volumes:", iname)
400
401
        ival.sort()
        for node, vol in ival:
402
          if node in bad_nodes:
403
            ToStdout("\tbroken node %s /dev/xenvg/%s", node, vol)
404
          else:
405
406
            ToStdout("\t%s /dev/xenvg/%s", node, vol)
    ToStdout("You need to run replace_disks for all the above"
407
408
           " instances, if this message persist after fixing nodes.")
    retcode |= 1
409
410
411
412

  return retcode


413
414
415
416
417
418
419
420
421
422
423
424
425
426
def RepairDiskSizes(opts, args):
  """Verify sizes of cluster disks.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: optional list of instances to restrict check to
  @rtype: int
  @return: the desired exit code

  """
  op = opcodes.OpRepairDiskSizes(instances=args)
  SubmitOpCode(op)


427
@UsesRPC
Iustin Pop's avatar
Iustin Pop committed
428
429
430
431
432
433
434
def MasterFailover(opts, args):
  """Failover the master node.

  This command, when run on a non-master node, will cause the current
  master to cease being master, and the non-master to become new
  master.

435
436
437
438
439
440
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code

Iustin Pop's avatar
Iustin Pop committed
441
  """
442
443
444
445
446
447
448
449
450
  if opts.no_voting:
    usertext = ("This will perform the failover even if most other nodes"
                " are down, or if this node is outdated. This is dangerous"
                " as it can lead to a non-consistent cluster. Check the"
                " gnt-cluster(8) man page before proceeding. Continue?")
    if not AskUser(usertext):
      return 1

  return bootstrap.MasterFailover(no_voting=opts.no_voting)
Iustin Pop's avatar
Iustin Pop committed
451
452


Iustin Pop's avatar
Iustin Pop committed
453
454
455
def SearchTags(opts, args):
  """Searches the tags on all the cluster.

456
457
458
459
460
461
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain only one element, the tag pattern
  @rtype: int
  @return: the desired exit code

Iustin Pop's avatar
Iustin Pop committed
462
463
464
465
466
467
468
469
  """
  op = opcodes.OpSearchTags(pattern=args[0])
  result = SubmitOpCode(op)
  if not result:
    return 1
  result = list(result)
  result.sort()
  for path, tag in result:
470
    ToStdout("%s %s", path, tag)
Iustin Pop's avatar
Iustin Pop committed
471
472


473
474
475
def SetClusterParams(opts, args):
  """Modify the cluster.

476
477
478
479
480
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should be an empty list
  @rtype: int
  @return: the desired exit code
481
482

  """
483
484
  if not (not opts.lvm_storage or opts.vg_name or
          opts.enabled_hypervisors or opts.hvparams or
485
486
          opts.beparams or opts.nicparams or
          opts.candidate_pool_size is not None):
487
    ToStderr("Please give at least one of the parameters.")
488
489
490
491
    return 1

  vg_name = opts.vg_name
  if not opts.lvm_storage and opts.vg_name:
492
    ToStdout("Options --no-lvm-storage and --vg-name conflict.")
493
    return 1
494
495
  elif not opts.lvm_storage:
    vg_name = ''
496

497
498
499
500
  hvlist = opts.enabled_hypervisors
  if hvlist is not None:
    hvlist = hvlist.split(",")

501
502
  # a list of (name, dict) we can pass directly to dict() (or [])
  hvparams = dict(opts.hvparams)
503
504
  for hv, hv_params in hvparams.iteritems():
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
505
506

  beparams = opts.beparams
507
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
508

509
510
511
  nicparams = opts.nicparams
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)

512
  op = opcodes.OpSetClusterParams(vg_name=vg_name,
513
514
                                  enabled_hypervisors=hvlist,
                                  hvparams=hvparams,
515
                                  beparams=beparams,
516
                                  nicparams=nicparams,
517
                                  candidate_pool_size=opts.candidate_pool_size)
518
519
520
521
  SubmitOpCode(op)
  return 0


522
523
524
def QueueOps(opts, args):
  """Queue operations.

525
526
527
528
529
530
  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain only one element, the subcommand
  @rtype: int
  @return: the desired exit code

531
532
533
534
535
536
537
538
539
  """
  command = args[0]
  client = GetClient()
  if command in ("drain", "undrain"):
    drain_flag = command == "drain"
    client.SetQueueDrainFlag(drain_flag)
  elif command == "info":
    result = client.QueryConfigValues(["drain_flag"])
    if result[0]:
540
      val = "set"
541
    else:
542
543
      val = "unset"
    ToStdout("The drain flag is %s" % val)
544
545
546
  else:
    raise errors.OpPrereqError("Command '%s' is not valid." % command)

547
548
  return 0

549

550
551
552
553
554
555
556
def _ShowWatcherPause(until):
  if until is None or until < time.time():
    ToStdout("The watcher is not paused.")
  else:
    ToStdout("The watcher is paused until %s.", time.ctime(until))


557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
def WatcherOps(opts, args):
  """Watcher operations.

  @param opts: the command line options selected by the user
  @type args: list
  @param args: should contain only one element, the subcommand
  @rtype: int
  @return: the desired exit code

  """
  command = args[0]
  client = GetClient()

  if command == "continue":
    client.SetWatcherPause(None)
572
    ToStdout("The watcher is no longer paused.")
573
574
575
576
577

  elif command == "pause":
    if len(args) < 2:
      raise errors.OpPrereqError("Missing pause duration")

578
579
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
    _ShowWatcherPause(result)
580
581
582

  elif command == "info":
    result = client.QueryConfigValues(["watcher_pause"])
583
    _ShowWatcherPause(result)
584
585
586
587
588
589
590

  else:
    raise errors.OpPrereqError("Command '%s' is not valid." % command)

  return 0


Iustin Pop's avatar
Iustin Pop committed
591
commands = {
Michael Hanselmann's avatar
Michael Hanselmann committed
592
  'init': (InitCluster, [ArgHost(min=1, max=1)],
Iustin Pop's avatar
Iustin Pop committed
593
           [DEBUG_OPT,
594
            SECONDARY_IP_OPT,
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
            cli_option("-m", "--mac-prefix", dest="mac_prefix",
                       help="Specify the mac prefix for the instance IP"
                       " addresses, in the format XX:XX:XX",
                       metavar="PREFIX",
                       default=constants.DEFAULT_MAC_PREFIX,),
            cli_option("-g", "--vg-name", dest="vg_name",
                       help="Specify the volume group name "
                       " (cluster-wide) for disk allocation [xenvg]",
                       metavar="VG",
                       default=None,),
            cli_option("--master-netdev", dest="master_netdev",
                       help="Specify the node interface (cluster-wide)"
                         " on which the master IP address will be added "
                         " [%s]" % constants.DEFAULT_BRIDGE,
                       metavar="NETDEV",
                       default=constants.DEFAULT_BRIDGE,),
            cli_option("--file-storage-dir", dest="file_storage_dir",
                       help="Specify the default directory (cluster-wide)"
                            " for storing the file-based disks [%s]" %
                            constants.DEFAULT_FILE_STORAGE_DIR,
                       metavar="DIR",
                       default=constants.DEFAULT_FILE_STORAGE_DIR,),
617
            NOLVM_STORAGE_OPT,
618
619
620
621
            cli_option("--no-etc-hosts", dest="modify_etc_hosts",
                       help="Don't modify /etc/hosts"
                            " (cluster-wide)",
                       action="store_false", default=True,),
622
            ENABLED_HV_OPT,
623
            HVLIST_OPT,
624
            BACKEND_OPT,
625
            NIC_PARAMS_OPT,
626
627
628
629
            cli_option("-C", "--candidate-pool-size",
                       default=constants.MASTER_POOL_SIZE_DEFAULT,
                       help="Set the candidate pool size",
                       dest="candidate_pool_size", type="int"),
Iustin Pop's avatar
Iustin Pop committed
630
            ],
631
           "[opts...] <cluster_name>",
Iustin Pop's avatar
Iustin Pop committed
632
           "Initialises a new cluster configuration"),
633
  'destroy': (DestroyCluster, ARGS_NONE,
Iustin Pop's avatar
Iustin Pop committed
634
              [DEBUG_OPT,
635
636
637
               cli_option("--yes-do-it", dest="yes_do_it",
                          help="Destroy cluster",
                          action="store_true"),
Iustin Pop's avatar
Iustin Pop committed
638
              ],
639
              "", "Destroy cluster"),
Michael Hanselmann's avatar
Michael Hanselmann committed
640
  'rename': (RenameCluster, [ArgHost(min=1, max=1)],
641
642
643
             [DEBUG_OPT, FORCE_OPT],
             "<new_name>",
             "Renames the cluster"),
644
  'redist-conf': (RedistributeConfig, ARGS_NONE, [DEBUG_OPT, SUBMIT_OPT],
645
646
647
                  "",
                  "Forces a push of the configuration file and ssconf files"
                  " to the nodes in the cluster"),
648
  'verify': (VerifyCluster, ARGS_NONE,
649
             [DEBUG_OPT, VERBOSE_OPT, DEBUG_SIMERR_OPT,
650
651
652
653
654
655
656
              cli_option("--error-codes", dest="error_codes",
                         help="Enable parseable error messages",
                         action="store_true", default=False),
              cli_option("--no-nplus1-mem", dest="skip_nplusone_mem",
                         help="Skip N+1 memory redundancy tests",
                         action="store_true", default=False),
              ],
657
             "", "Does a check on the cluster configuration"),
658
  'verify-disks': (VerifyDisks, ARGS_NONE, [DEBUG_OPT],
659
                   "", "Does a check on the cluster disk status"),
660
  'repair-disk-sizes': (RepairDiskSizes, ARGS_MANY_INSTANCES, [DEBUG_OPT],
661
                   "", "Updates mismatches in recorded disk sizes"),
662
  'masterfailover': (MasterFailover, ARGS_NONE, [DEBUG_OPT,
663
664
665
666
                     cli_option("--no-voting", dest="no_voting",
                                help="Skip node agreement check (dangerous)",
                                action="store_true",
                                default=False,),
667
                     ],
668
                     "", "Makes the current node the master"),
669
  'version': (ShowClusterVersion, ARGS_NONE, [DEBUG_OPT],
670
              "", "Shows the cluster version"),
671
  'getmaster': (ShowClusterMaster, ARGS_NONE, [DEBUG_OPT],
672
                "", "Shows the cluster master"),
673
  'copyfile': (ClusterCopyFile, [ArgFile(min=1, max=1)],
674
               [DEBUG_OPT, NODE_LIST_OPT],
675
               "[-n node...] <filename>",
Iustin Pop's avatar
Iustin Pop committed
676
               "Copies a file to all (or only some) nodes"),
677
678
  'command': (RunClusterCommand, [ArgCommand(min=1)],
              [DEBUG_OPT, NODE_LIST_OPT],
679
              "[-n node...] <command>",
Iustin Pop's avatar
Iustin Pop committed
680
              "Runs a command on all (or only some) nodes"),
681
  'info': (ShowClusterConfig, ARGS_NONE, [DEBUG_OPT],
682
           "", "Show cluster configuration"),
683
  'list-tags': (ListTags, ARGS_NONE,
684
                [DEBUG_OPT], "", "List the tags of the cluster"),
685
  'add-tags': (AddTags, [ArgUnknown()], [DEBUG_OPT, TAG_SRC_OPT],
686
               "tag...", "Add tags to the cluster"),
687
  'remove-tags': (RemoveTags, [ArgUnknown()], [DEBUG_OPT, TAG_SRC_OPT],
688
                  "tag...", "Remove tags from the cluster"),
689
  'search-tags': (SearchTags, [ArgUnknown(min=1, max=1)],
690
                  [DEBUG_OPT], "", "Searches the tags on all objects on"
Iustin Pop's avatar
Iustin Pop committed
691
                  " the cluster for a given pattern (regex)"),
692
693
694
  'queue': (QueueOps,
            [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
            [DEBUG_OPT],
695
            "drain|undrain|info", "Change queue properties"),
696
697
698
699
700
701
  'watcher': (WatcherOps,
              [ArgChoice(min=1, max=1,
                         choices=["pause", "continue", "info"]),
               ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
              [DEBUG_OPT],
              "{pause <timespec>|continue|info}", "Change watcher properties"),
702
  'modify': (SetClusterParams, ARGS_NONE,
703
             [DEBUG_OPT,
704
705
706
707
708
              cli_option("-g", "--vg-name", dest="vg_name",
                         help="Specify the volume group name "
                         " (cluster-wide) for disk allocation "
                         "and enable lvm based storage",
                         metavar="VG",),
709
              NOLVM_STORAGE_OPT,
710
              ENABLED_HV_OPT,
711
              HVLIST_OPT,
712
              BACKEND_OPT,
713
              NIC_PARAMS_OPT,
714
715
716
              cli_option("-C", "--candidate-pool-size", default=None,
                         help="Set the candidate pool size",
                         dest="candidate_pool_size", type="int"),
717
718
719
              ],
             "[opts...]",
             "Alters the parameters of the cluster"),
Iustin Pop's avatar
Iustin Pop committed
720
721
722
  }

if __name__ == '__main__':
723
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))