Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ 1f587d3d

History | View | Annotate | Download (22.1 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 2f79bd34 Iustin Pop
# pylint: disable-msg=W0401,W0614
23 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
24 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
25 2f79bd34 Iustin Pop
26 a8083063 Iustin Pop
import sys
27 b3989551 Iustin Pop
import os.path
28 95b2e626 Michael Hanselmann
import time
29 a8083063 Iustin Pop
30 a8083063 Iustin Pop
from ganeti.cli import *
31 a8083063 Iustin Pop
from ganeti import opcodes
32 c2a62a33 Michael Hanselmann
from ganeti import constants
33 f4d4e184 Iustin Pop
from ganeti import errors
34 b63ed789 Iustin Pop
from ganeti import utils
35 a0c9f010 Michael Hanselmann
from ganeti import bootstrap
36 b3989551 Iustin Pop
from ganeti import ssh
37 d3cfe525 Guido Trotter
from ganeti import objects
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
40 4331f6cd Michael Hanselmann
@UsesRPC
41 a8083063 Iustin Pop
def InitCluster(opts, args):
42 a8083063 Iustin Pop
  """Initialize the cluster.
43 a8083063 Iustin Pop
44 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
45 469ee405 Iustin Pop
  @type args: list
46 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
47 469ee405 Iustin Pop
      cluster name
48 469ee405 Iustin Pop
  @rtype: int
49 469ee405 Iustin Pop
  @return: the desired exit code
50 a8083063 Iustin Pop
51 a8083063 Iustin Pop
  """
52 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
53 3a24c527 Iustin Pop
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
54 90b6aa3a Manuel Franceschini
    return 1
55 90b6aa3a Manuel Franceschini
56 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
57 90b6aa3a Manuel Franceschini
  if opts.lvm_storage and not opts.vg_name:
58 90b6aa3a Manuel Franceschini
    vg_name = constants.DEFAULT_VG
59 90b6aa3a Manuel Franceschini
60 ea3a925f Alexander Schreiber
  hvlist = opts.enabled_hypervisors
61 383a3591 Iustin Pop
  if hvlist is None:
62 383a3591 Iustin Pop
    hvlist = constants.DEFAULT_ENABLED_HYPERVISOR
63 066f465d Guido Trotter
  hvlist = hvlist.split(",")
64 ea3a925f Alexander Schreiber
65 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
66 ea3a925f Alexander Schreiber
  beparams = opts.beparams
67 b6a30b0d Guido Trotter
  nicparams = opts.nicparams
68 ea3a925f Alexander Schreiber
69 ea3a925f Alexander Schreiber
  # prepare beparams dict
70 d3cfe525 Guido Trotter
  beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams)
71 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
72 ea3a925f Alexander Schreiber
73 b6a30b0d Guido Trotter
  # prepare nicparams dict
74 b6a30b0d Guido Trotter
  nicparams = objects.FillDict(constants.NICC_DEFAULTS, nicparams)
75 b6a30b0d Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
76 b6a30b0d Guido Trotter
77 ea3a925f Alexander Schreiber
  # prepare hvparams dict
78 ea3a925f Alexander Schreiber
  for hv in constants.HYPER_TYPES:
79 ea3a925f Alexander Schreiber
    if hv not in hvparams:
80 ea3a925f Alexander Schreiber
      hvparams[hv] = {}
81 d3cfe525 Guido Trotter
    hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv])
82 a5728081 Guido Trotter
    utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES)
83 ea3a925f Alexander Schreiber
84 e32df528 Iustin Pop
  if opts.candidate_pool_size is None:
85 e32df528 Iustin Pop
    opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT
86 e32df528 Iustin Pop
87 a0c9f010 Michael Hanselmann
  bootstrap.InitCluster(cluster_name=args[0],
88 a0c9f010 Michael Hanselmann
                        secondary_ip=opts.secondary_ip,
89 a0c9f010 Michael Hanselmann
                        vg_name=vg_name,
90 a0c9f010 Michael Hanselmann
                        mac_prefix=opts.mac_prefix,
91 a0c9f010 Michael Hanselmann
                        master_netdev=opts.master_netdev,
92 ea3a925f Alexander Schreiber
                        file_storage_dir=opts.file_storage_dir,
93 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
94 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
95 ce735215 Guido Trotter
                        beparams=beparams,
96 b6a30b0d Guido Trotter
                        nicparams=nicparams,
97 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
98 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
99 ce735215 Guido Trotter
                        )
100 3552cd2e Luca Bigliardi
  op = opcodes.OpPostInitCluster()
101 3552cd2e Luca Bigliardi
  SubmitOpCode(op)
102 a8083063 Iustin Pop
  return 0
103 a8083063 Iustin Pop
104 a8083063 Iustin Pop
105 4331f6cd Michael Hanselmann
@UsesRPC
106 a8083063 Iustin Pop
def DestroyCluster(opts, args):
107 a8083063 Iustin Pop
  """Destroy the cluster.
108 a8083063 Iustin Pop
109 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
110 469ee405 Iustin Pop
  @type args: list
111 469ee405 Iustin Pop
  @param args: should be an empty list
112 469ee405 Iustin Pop
  @rtype: int
113 469ee405 Iustin Pop
  @return: the desired exit code
114 098c0958 Michael Hanselmann
115 a8083063 Iustin Pop
  """
116 a8083063 Iustin Pop
  if not opts.yes_do_it:
117 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
118 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
119 a8083063 Iustin Pop
    return 1
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
  op = opcodes.OpDestroyCluster()
122 140aa4a8 Iustin Pop
  master = SubmitOpCode(op)
123 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
124 140aa4a8 Iustin Pop
  # shutdown all the daemons
125 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
126 a8083063 Iustin Pop
  return 0
127 a8083063 Iustin Pop
128 a8083063 Iustin Pop
129 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
130 07bd8a51 Iustin Pop
  """Rename the cluster.
131 07bd8a51 Iustin Pop
132 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
133 469ee405 Iustin Pop
  @type args: list
134 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
135 469ee405 Iustin Pop
  @rtype: int
136 469ee405 Iustin Pop
  @return: the desired exit code
137 07bd8a51 Iustin Pop
138 07bd8a51 Iustin Pop
  """
139 07bd8a51 Iustin Pop
  name = args[0]
140 07bd8a51 Iustin Pop
  if not opts.force:
141 07bd8a51 Iustin Pop
    usertext = ("This will rename the cluster to '%s'. If you are connected"
142 07bd8a51 Iustin Pop
                " over the network to the cluster name, the operation is very"
143 07bd8a51 Iustin Pop
                " dangerous as the IP address will be removed from the node"
144 07bd8a51 Iustin Pop
                " and the change may not go through. Continue?") % name
145 47988778 Iustin Pop
    if not AskUser(usertext):
146 07bd8a51 Iustin Pop
      return 1
147 07bd8a51 Iustin Pop
148 07bd8a51 Iustin Pop
  op = opcodes.OpRenameCluster(name=name)
149 07bd8a51 Iustin Pop
  SubmitOpCode(op)
150 07bd8a51 Iustin Pop
  return 0
151 07bd8a51 Iustin Pop
152 07bd8a51 Iustin Pop
153 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
154 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
155 afee0879 Iustin Pop
156 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
157 afee0879 Iustin Pop
  @type args: list
158 afee0879 Iustin Pop
  @param args: empty list
159 afee0879 Iustin Pop
  @rtype: int
160 afee0879 Iustin Pop
  @return: the desired exit code
161 afee0879 Iustin Pop
162 afee0879 Iustin Pop
  """
163 81a49123 Iustin Pop
  op = opcodes.OpRedistributeConfig()
164 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
165 afee0879 Iustin Pop
  return 0
166 afee0879 Iustin Pop
167 afee0879 Iustin Pop
168 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
169 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
170 a8083063 Iustin Pop
171 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
172 469ee405 Iustin Pop
  @type args: list
173 469ee405 Iustin Pop
  @param args: should be an empty list
174 469ee405 Iustin Pop
  @rtype: int
175 469ee405 Iustin Pop
  @return: the desired exit code
176 a8083063 Iustin Pop
177 a8083063 Iustin Pop
  """
178 2e7b8369 Iustin Pop
  cl = GetClient()
179 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
180 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
181 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
182 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
183 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
184 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
185 a8083063 Iustin Pop
  return 0
186 a8083063 Iustin Pop
187 a8083063 Iustin Pop
188 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
189 a8083063 Iustin Pop
  """Write name of master node to the standard output.
190 a8083063 Iustin Pop
191 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
192 469ee405 Iustin Pop
  @type args: list
193 469ee405 Iustin Pop
  @param args: should be an empty list
194 469ee405 Iustin Pop
  @rtype: int
195 469ee405 Iustin Pop
  @return: the desired exit code
196 a8083063 Iustin Pop
197 a8083063 Iustin Pop
  """
198 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
199 8eb148ae Iustin Pop
  ToStdout(master)
200 a8083063 Iustin Pop
  return 0
201 a8083063 Iustin Pop
202 1094acda Guido Trotter
def _PrintGroupedParams(paramsdict):
203 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
204 1094acda Guido Trotter
205 1094acda Guido Trotter
  @type paramsdict: dict of dicts
206 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
207 1094acda Guido Trotter
208 1094acda Guido Trotter
  """
209 1094acda Guido Trotter
  for gr_name, gr_dict in paramsdict.items():
210 1094acda Guido Trotter
    ToStdout("  - %s:", gr_name)
211 1094acda Guido Trotter
    for item, val in gr_dict.iteritems():
212 1094acda Guido Trotter
      ToStdout("      %s: %s", item, val)
213 a8083063 Iustin Pop
214 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
215 a8083063 Iustin Pop
  """Shows cluster information.
216 a8083063 Iustin Pop
217 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
218 469ee405 Iustin Pop
  @type args: list
219 469ee405 Iustin Pop
  @param args: should be an empty list
220 469ee405 Iustin Pop
  @rtype: int
221 469ee405 Iustin Pop
  @return: the desired exit code
222 469ee405 Iustin Pop
223 a8083063 Iustin Pop
  """
224 2e7b8369 Iustin Pop
  cl = GetClient()
225 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
226 a8083063 Iustin Pop
227 3a24c527 Iustin Pop
  ToStdout("Cluster name: %s", result["name"])
228 a8083063 Iustin Pop
229 90f72445 Iustin Pop
  ToStdout("Creation time: %s", utils.FormatTime(result["ctime"]))
230 90f72445 Iustin Pop
  ToStdout("Modification time: %s", utils.FormatTime(result["mtime"]))
231 90f72445 Iustin Pop
232 3a24c527 Iustin Pop
  ToStdout("Master node: %s", result["master"])
233 a8083063 Iustin Pop
234 3a24c527 Iustin Pop
  ToStdout("Architecture (this node): %s (%s)",
235 3a24c527 Iustin Pop
           result["architecture"][0], result["architecture"][1])
236 a8083063 Iustin Pop
237 c118d1f4 Michael Hanselmann
  if result["tags"]:
238 c118d1f4 Michael Hanselmann
    tags = ", ".join(utils.NiceSort(result["tags"]))
239 c118d1f4 Michael Hanselmann
  else:
240 c118d1f4 Michael Hanselmann
    tags = "(none)"
241 c118d1f4 Michael Hanselmann
242 c118d1f4 Michael Hanselmann
  ToStdout("Tags: %s", tags)
243 c118d1f4 Michael Hanselmann
244 02691904 Alexander Schreiber
  ToStdout("Default hypervisor: %s", result["default_hypervisor"])
245 3a24c527 Iustin Pop
  ToStdout("Enabled hypervisors: %s", ", ".join(result["enabled_hypervisors"]))
246 469f88e1 Iustin Pop
247 3a24c527 Iustin Pop
  ToStdout("Hypervisor parameters:")
248 1094acda Guido Trotter
  _PrintGroupedParams(result["hvparams"])
249 469f88e1 Iustin Pop
250 3a24c527 Iustin Pop
  ToStdout("Cluster parameters:")
251 4b7735f9 Iustin Pop
  ToStdout("  - candidate pool size: %s", result["candidate_pool_size"])
252 a8001106 Guido Trotter
  ToStdout("  - master netdev: %s", result["master_netdev"])
253 a8001106 Guido Trotter
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
254 a8001106 Guido Trotter
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
255 4b7735f9 Iustin Pop
256 4b7735f9 Iustin Pop
  ToStdout("Default instance parameters:")
257 1094acda Guido Trotter
  _PrintGroupedParams(result["beparams"])
258 1094acda Guido Trotter
259 1094acda Guido Trotter
  ToStdout("Default nic parameters:")
260 1094acda Guido Trotter
  _PrintGroupedParams(result["nicparams"])
261 8a12ce45 Iustin Pop
262 a8083063 Iustin Pop
  return 0
263 a8083063 Iustin Pop
264 a8083063 Iustin Pop
265 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
266 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
267 a8083063 Iustin Pop
268 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
269 469ee405 Iustin Pop
  @type args: list
270 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
271 469ee405 Iustin Pop
      the file to be copied
272 469ee405 Iustin Pop
  @rtype: int
273 469ee405 Iustin Pop
  @return: the desired exit code
274 a8083063 Iustin Pop
275 a8083063 Iustin Pop
  """
276 b3989551 Iustin Pop
  filename = args[0]
277 b3989551 Iustin Pop
  if not os.path.exists(filename):
278 b3989551 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename)
279 b3989551 Iustin Pop
280 56bece1f Iustin Pop
  cl = GetClient()
281 56bece1f Iustin Pop
282 b3989551 Iustin Pop
  myname = utils.HostInfo().name
283 b3989551 Iustin Pop
284 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
285 56bece1f Iustin Pop
286 4040a784 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl)
287 4040a784 Iustin Pop
  results = [name for name in results if name != myname]
288 e00ea635 Michael Hanselmann
289 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
290 b3989551 Iustin Pop
  for node in results:
291 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
292 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
293 b3989551 Iustin Pop
294 a8083063 Iustin Pop
  return 0
295 a8083063 Iustin Pop
296 a8083063 Iustin Pop
297 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
298 a8083063 Iustin Pop
  """Run a command on some nodes.
299 a8083063 Iustin Pop
300 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
301 469ee405 Iustin Pop
  @type args: list
302 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
303 469ee405 Iustin Pop
  @rtype: int
304 469ee405 Iustin Pop
  @return: the desired exit code
305 a8083063 Iustin Pop
306 a8083063 Iustin Pop
  """
307 56bece1f Iustin Pop
  cl = GetClient()
308 7688d0d3 Michael Hanselmann
309 a8083063 Iustin Pop
  command = " ".join(args)
310 4040a784 Iustin Pop
311 4040a784 Iustin Pop
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl)
312 56bece1f Iustin Pop
313 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
314 56bece1f Iustin Pop
                                                    "master_node"])
315 b3989551 Iustin Pop
316 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
317 b3989551 Iustin Pop
318 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
319 b3989551 Iustin Pop
  if master_node in nodes:
320 b3989551 Iustin Pop
    nodes.remove(master_node)
321 b3989551 Iustin Pop
    nodes.append(master_node)
322 b3989551 Iustin Pop
323 b3989551 Iustin Pop
  for name in nodes:
324 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
325 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
326 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
327 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
328 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
329 b3989551 Iustin Pop
330 b3989551 Iustin Pop
  return 0
331 a8083063 Iustin Pop
332 a8083063 Iustin Pop
333 a8083063 Iustin Pop
def VerifyCluster(opts, args):
334 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
335 a8083063 Iustin Pop
336 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
337 469ee405 Iustin Pop
  @type args: list
338 469ee405 Iustin Pop
  @param args: should be an empty list
339 469ee405 Iustin Pop
  @rtype: int
340 469ee405 Iustin Pop
  @return: the desired exit code
341 a8083063 Iustin Pop
342 a8083063 Iustin Pop
  """
343 8d59409f Iustin Pop
  skip_checks = []
344 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
345 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
346 7c874ee1 Iustin Pop
  op = opcodes.OpVerifyCluster(skip_checks=skip_checks,
347 7c874ee1 Iustin Pop
                               verbose=opts.verbose,
348 a0c9776a Iustin Pop
                               error_codes=opts.error_codes,
349 a0c9776a Iustin Pop
                               debug_simulate_errors=opts.simulate_errors)
350 34290825 Michael Hanselmann
  if SubmitOpCode(op):
351 34290825 Michael Hanselmann
    return 0
352 34290825 Michael Hanselmann
  else:
353 34290825 Michael Hanselmann
    return 1
354 a8083063 Iustin Pop
355 a8083063 Iustin Pop
356 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
357 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
358 f4d4e184 Iustin Pop
359 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
360 469ee405 Iustin Pop
  @type args: list
361 469ee405 Iustin Pop
  @param args: should be an empty list
362 469ee405 Iustin Pop
  @rtype: int
363 469ee405 Iustin Pop
  @return: the desired exit code
364 f4d4e184 Iustin Pop
365 f4d4e184 Iustin Pop
  """
366 f4d4e184 Iustin Pop
  op = opcodes.OpVerifyDisks()
367 f4d4e184 Iustin Pop
  result = SubmitOpCode(op)
368 29d376ec Iustin Pop
  if not isinstance(result, (list, tuple)) or len(result) != 3:
369 f4d4e184 Iustin Pop
    raise errors.ProgrammerError("Unknown result type for OpVerifyDisks")
370 f4d4e184 Iustin Pop
371 29d376ec Iustin Pop
  bad_nodes, instances, missing = result
372 b63ed789 Iustin Pop
373 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
374 b63ed789 Iustin Pop
375 29d376ec Iustin Pop
  if bad_nodes:
376 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
377 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
378 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
379 b63ed789 Iustin Pop
      retcode |= 1
380 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
381 b63ed789 Iustin Pop
382 f4d4e184 Iustin Pop
  if instances:
383 f4d4e184 Iustin Pop
    for iname in instances:
384 b63ed789 Iustin Pop
      if iname in missing:
385 b63ed789 Iustin Pop
        continue
386 f4d4e184 Iustin Pop
      op = opcodes.OpActivateInstanceDisks(instance_name=iname)
387 f4d4e184 Iustin Pop
      try:
388 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
389 f4d4e184 Iustin Pop
        SubmitOpCode(op)
390 f4d4e184 Iustin Pop
      except errors.GenericError, err:
391 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
392 f4d4e184 Iustin Pop
        retcode |= nret
393 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
394 b63ed789 Iustin Pop
395 b63ed789 Iustin Pop
  if missing:
396 b63ed789 Iustin Pop
    for iname, ival in missing.iteritems():
397 29d376ec Iustin Pop
      all_missing = utils.all(ival, lambda x: x[0] in bad_nodes)
398 b63ed789 Iustin Pop
      if all_missing:
399 3a24c527 Iustin Pop
        ToStdout("Instance %s cannot be verified as it lives on"
400 3a24c527 Iustin Pop
                 " broken nodes", iname)
401 b63ed789 Iustin Pop
      else:
402 3a24c527 Iustin Pop
        ToStdout("Instance %s has missing logical volumes:", iname)
403 b63ed789 Iustin Pop
        ival.sort()
404 b63ed789 Iustin Pop
        for node, vol in ival:
405 29d376ec Iustin Pop
          if node in bad_nodes:
406 3a24c527 Iustin Pop
            ToStdout("\tbroken node %s /dev/xenvg/%s", node, vol)
407 b63ed789 Iustin Pop
          else:
408 3a24c527 Iustin Pop
            ToStdout("\t%s /dev/xenvg/%s", node, vol)
409 3a24c527 Iustin Pop
    ToStdout("You need to run replace_disks for all the above"
410 b63ed789 Iustin Pop
           " instances, if this message persist after fixing nodes.")
411 b63ed789 Iustin Pop
    retcode |= 1
412 f4d4e184 Iustin Pop
413 f4d4e184 Iustin Pop
  return retcode
414 f4d4e184 Iustin Pop
415 f4d4e184 Iustin Pop
416 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
417 60975797 Iustin Pop
  """Verify sizes of cluster disks.
418 60975797 Iustin Pop
419 60975797 Iustin Pop
  @param opts: the command line options selected by the user
420 60975797 Iustin Pop
  @type args: list
421 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
422 60975797 Iustin Pop
  @rtype: int
423 60975797 Iustin Pop
  @return: the desired exit code
424 60975797 Iustin Pop
425 60975797 Iustin Pop
  """
426 60975797 Iustin Pop
  op = opcodes.OpRepairDiskSizes(instances=args)
427 60975797 Iustin Pop
  SubmitOpCode(op)
428 60975797 Iustin Pop
429 60975797 Iustin Pop
430 4331f6cd Michael Hanselmann
@UsesRPC
431 a8083063 Iustin Pop
def MasterFailover(opts, args):
432 a8083063 Iustin Pop
  """Failover the master node.
433 a8083063 Iustin Pop
434 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
435 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
436 a8083063 Iustin Pop
  master.
437 a8083063 Iustin Pop
438 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
439 469ee405 Iustin Pop
  @type args: list
440 469ee405 Iustin Pop
  @param args: should be an empty list
441 469ee405 Iustin Pop
  @rtype: int
442 469ee405 Iustin Pop
  @return: the desired exit code
443 469ee405 Iustin Pop
444 a8083063 Iustin Pop
  """
445 8e2524c3 Guido Trotter
  if opts.no_voting:
446 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
447 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
448 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
449 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
450 8e2524c3 Guido Trotter
    if not AskUser(usertext):
451 8e2524c3 Guido Trotter
      return 1
452 8e2524c3 Guido Trotter
453 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
454 a8083063 Iustin Pop
455 a8083063 Iustin Pop
456 73415719 Iustin Pop
def SearchTags(opts, args):
457 73415719 Iustin Pop
  """Searches the tags on all the cluster.
458 73415719 Iustin Pop
459 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
460 469ee405 Iustin Pop
  @type args: list
461 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
462 469ee405 Iustin Pop
  @rtype: int
463 469ee405 Iustin Pop
  @return: the desired exit code
464 469ee405 Iustin Pop
465 73415719 Iustin Pop
  """
466 73415719 Iustin Pop
  op = opcodes.OpSearchTags(pattern=args[0])
467 73415719 Iustin Pop
  result = SubmitOpCode(op)
468 73415719 Iustin Pop
  if not result:
469 73415719 Iustin Pop
    return 1
470 73415719 Iustin Pop
  result = list(result)
471 73415719 Iustin Pop
  result.sort()
472 73415719 Iustin Pop
  for path, tag in result:
473 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
474 73415719 Iustin Pop
475 73415719 Iustin Pop
476 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
477 90b6aa3a Manuel Franceschini
  """Modify the cluster.
478 90b6aa3a Manuel Franceschini
479 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
480 469ee405 Iustin Pop
  @type args: list
481 469ee405 Iustin Pop
  @param args: should be an empty list
482 469ee405 Iustin Pop
  @rtype: int
483 469ee405 Iustin Pop
  @return: the desired exit code
484 90b6aa3a Manuel Franceschini
485 90b6aa3a Manuel Franceschini
  """
486 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
487 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
488 5af3da74 Guido Trotter
          opts.beparams or opts.nicparams or
489 5af3da74 Guido Trotter
          opts.candidate_pool_size is not None):
490 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
491 90b6aa3a Manuel Franceschini
    return 1
492 90b6aa3a Manuel Franceschini
493 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
494 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
495 3a24c527 Iustin Pop
    ToStdout("Options --no-lvm-storage and --vg-name conflict.")
496 90b6aa3a Manuel Franceschini
    return 1
497 b8a8fbe1 Guido Trotter
  elif not opts.lvm_storage:
498 b8a8fbe1 Guido Trotter
    vg_name = ''
499 90b6aa3a Manuel Franceschini
500 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
501 779c15bb Iustin Pop
  if hvlist is not None:
502 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
503 779c15bb Iustin Pop
504 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
505 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
506 a5728081 Guido Trotter
  for hv, hv_params in hvparams.iteritems():
507 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
508 779c15bb Iustin Pop
509 779c15bb Iustin Pop
  beparams = opts.beparams
510 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
511 779c15bb Iustin Pop
512 5af3da74 Guido Trotter
  nicparams = opts.nicparams
513 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
514 5af3da74 Guido Trotter
515 b8a8fbe1 Guido Trotter
  op = opcodes.OpSetClusterParams(vg_name=vg_name,
516 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
517 779c15bb Iustin Pop
                                  hvparams=hvparams,
518 4b7735f9 Iustin Pop
                                  beparams=beparams,
519 5af3da74 Guido Trotter
                                  nicparams=nicparams,
520 4b7735f9 Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size)
521 90b6aa3a Manuel Franceschini
  SubmitOpCode(op)
522 90b6aa3a Manuel Franceschini
  return 0
523 90b6aa3a Manuel Franceschini
524 90b6aa3a Manuel Franceschini
525 3ccafd0e Iustin Pop
def QueueOps(opts, args):
526 3ccafd0e Iustin Pop
  """Queue operations.
527 3ccafd0e Iustin Pop
528 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
529 469ee405 Iustin Pop
  @type args: list
530 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
531 469ee405 Iustin Pop
  @rtype: int
532 469ee405 Iustin Pop
  @return: the desired exit code
533 469ee405 Iustin Pop
534 3ccafd0e Iustin Pop
  """
535 3ccafd0e Iustin Pop
  command = args[0]
536 3ccafd0e Iustin Pop
  client = GetClient()
537 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
538 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
539 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
540 3ccafd0e Iustin Pop
  elif command == "info":
541 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
542 3ccafd0e Iustin Pop
    if result[0]:
543 3a24c527 Iustin Pop
      val = "set"
544 3ccafd0e Iustin Pop
    else:
545 3a24c527 Iustin Pop
      val = "unset"
546 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
547 2e668b38 Guido Trotter
  else:
548 2e668b38 Guido Trotter
    raise errors.OpPrereqError("Command '%s' is not valid." % command)
549 2e668b38 Guido Trotter
550 3ccafd0e Iustin Pop
  return 0
551 3ccafd0e Iustin Pop
552 95b2e626 Michael Hanselmann
553 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
554 28b498cd Michael Hanselmann
  if until is None or until < time.time():
555 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
556 28b498cd Michael Hanselmann
  else:
557 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
558 28b498cd Michael Hanselmann
559 28b498cd Michael Hanselmann
560 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
561 95b2e626 Michael Hanselmann
  """Watcher operations.
562 95b2e626 Michael Hanselmann
563 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
564 95b2e626 Michael Hanselmann
  @type args: list
565 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
566 95b2e626 Michael Hanselmann
  @rtype: int
567 95b2e626 Michael Hanselmann
  @return: the desired exit code
568 95b2e626 Michael Hanselmann
569 95b2e626 Michael Hanselmann
  """
570 95b2e626 Michael Hanselmann
  command = args[0]
571 95b2e626 Michael Hanselmann
  client = GetClient()
572 95b2e626 Michael Hanselmann
573 95b2e626 Michael Hanselmann
  if command == "continue":
574 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
575 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
576 95b2e626 Michael Hanselmann
577 95b2e626 Michael Hanselmann
  elif command == "pause":
578 95b2e626 Michael Hanselmann
    if len(args) < 2:
579 95b2e626 Michael Hanselmann
      raise errors.OpPrereqError("Missing pause duration")
580 95b2e626 Michael Hanselmann
581 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
582 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
583 95b2e626 Michael Hanselmann
584 95b2e626 Michael Hanselmann
  elif command == "info":
585 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
586 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
587 95b2e626 Michael Hanselmann
588 95b2e626 Michael Hanselmann
  else:
589 95b2e626 Michael Hanselmann
    raise errors.OpPrereqError("Command '%s' is not valid." % command)
590 95b2e626 Michael Hanselmann
591 95b2e626 Michael Hanselmann
  return 0
592 95b2e626 Michael Hanselmann
593 95b2e626 Michael Hanselmann
594 a8083063 Iustin Pop
commands = {
595 83ec7961 Michael Hanselmann
  'init': (InitCluster, [ArgHost(min=1, max=1)],
596 a8083063 Iustin Pop
           [DEBUG_OPT,
597 8d823629 Iustin Pop
            SECONDARY_IP_OPT,
598 c38c44ad Michael Hanselmann
            cli_option("-m", "--mac-prefix", dest="mac_prefix",
599 c38c44ad Michael Hanselmann
                       help="Specify the mac prefix for the instance IP"
600 c38c44ad Michael Hanselmann
                       " addresses, in the format XX:XX:XX",
601 c38c44ad Michael Hanselmann
                       metavar="PREFIX",
602 c38c44ad Michael Hanselmann
                       default=constants.DEFAULT_MAC_PREFIX,),
603 b58726e8 Iustin Pop
            VG_NAME_OPT,
604 c38c44ad Michael Hanselmann
            cli_option("--master-netdev", dest="master_netdev",
605 c38c44ad Michael Hanselmann
                       help="Specify the node interface (cluster-wide)"
606 c38c44ad Michael Hanselmann
                         " on which the master IP address will be added "
607 c38c44ad Michael Hanselmann
                         " [%s]" % constants.DEFAULT_BRIDGE,
608 c38c44ad Michael Hanselmann
                       metavar="NETDEV",
609 c38c44ad Michael Hanselmann
                       default=constants.DEFAULT_BRIDGE,),
610 c38c44ad Michael Hanselmann
            cli_option("--file-storage-dir", dest="file_storage_dir",
611 c38c44ad Michael Hanselmann
                       help="Specify the default directory (cluster-wide)"
612 c38c44ad Michael Hanselmann
                            " for storing the file-based disks [%s]" %
613 c38c44ad Michael Hanselmann
                            constants.DEFAULT_FILE_STORAGE_DIR,
614 c38c44ad Michael Hanselmann
                       metavar="DIR",
615 c38c44ad Michael Hanselmann
                       default=constants.DEFAULT_FILE_STORAGE_DIR,),
616 831040bf Iustin Pop
            NOLVM_STORAGE_OPT,
617 c38c44ad Michael Hanselmann
            cli_option("--no-etc-hosts", dest="modify_etc_hosts",
618 c38c44ad Michael Hanselmann
                       help="Don't modify /etc/hosts"
619 c38c44ad Michael Hanselmann
                            " (cluster-wide)",
620 c38c44ad Michael Hanselmann
                       action="store_false", default=True,),
621 383a3591 Iustin Pop
            ENABLED_HV_OPT,
622 073271f6 Iustin Pop
            HVLIST_OPT,
623 087ed2ed Iustin Pop
            BACKEND_OPT,
624 4fbc93dd Iustin Pop
            NIC_PARAMS_OPT,
625 e32df528 Iustin Pop
            CP_SIZE_OPT,
626 a8083063 Iustin Pop
            ],
627 9a033156 Iustin Pop
           "[opts...] <cluster_name>",
628 a8083063 Iustin Pop
           "Initialises a new cluster configuration"),
629 4a265c08 Michael Hanselmann
  'destroy': (DestroyCluster, ARGS_NONE,
630 1f587d3d Iustin Pop
              [DEBUG_OPT, YES_DOIT_OPT],
631 9a033156 Iustin Pop
              "", "Destroy cluster"),
632 83ec7961 Michael Hanselmann
  'rename': (RenameCluster, [ArgHost(min=1, max=1)],
633 a8005e17 Michael Hanselmann
             [DEBUG_OPT, FORCE_OPT],
634 a8005e17 Michael Hanselmann
             "<new_name>",
635 a8005e17 Michael Hanselmann
             "Renames the cluster"),
636 4a265c08 Michael Hanselmann
  'redist-conf': (RedistributeConfig, ARGS_NONE, [DEBUG_OPT, SUBMIT_OPT],
637 afee0879 Iustin Pop
                  "",
638 afee0879 Iustin Pop
                  "Forces a push of the configuration file and ssconf files"
639 afee0879 Iustin Pop
                  " to the nodes in the cluster"),
640 7c874ee1 Iustin Pop
  'verify': (VerifyCluster, ARGS_NONE,
641 a0c9776a Iustin Pop
             [DEBUG_OPT, VERBOSE_OPT, DEBUG_SIMERR_OPT,
642 7c874ee1 Iustin Pop
              cli_option("--error-codes", dest="error_codes",
643 7c874ee1 Iustin Pop
                         help="Enable parseable error messages",
644 7c874ee1 Iustin Pop
                         action="store_true", default=False),
645 7c874ee1 Iustin Pop
              cli_option("--no-nplus1-mem", dest="skip_nplusone_mem",
646 7c874ee1 Iustin Pop
                         help="Skip N+1 memory redundancy tests",
647 7c874ee1 Iustin Pop
                         action="store_true", default=False),
648 7c874ee1 Iustin Pop
              ],
649 9a033156 Iustin Pop
             "", "Does a check on the cluster configuration"),
650 4a265c08 Michael Hanselmann
  'verify-disks': (VerifyDisks, ARGS_NONE, [DEBUG_OPT],
651 9a033156 Iustin Pop
                   "", "Does a check on the cluster disk status"),
652 4a265c08 Michael Hanselmann
  'repair-disk-sizes': (RepairDiskSizes, ARGS_MANY_INSTANCES, [DEBUG_OPT],
653 60975797 Iustin Pop
                   "", "Updates mismatches in recorded disk sizes"),
654 4a265c08 Michael Hanselmann
  'masterfailover': (MasterFailover, ARGS_NONE, [DEBUG_OPT,
655 c38c44ad Michael Hanselmann
                     cli_option("--no-voting", dest="no_voting",
656 c38c44ad Michael Hanselmann
                                help="Skip node agreement check (dangerous)",
657 c38c44ad Michael Hanselmann
                                action="store_true",
658 c38c44ad Michael Hanselmann
                                default=False,),
659 8e2524c3 Guido Trotter
                     ],
660 9a033156 Iustin Pop
                     "", "Makes the current node the master"),
661 4a265c08 Michael Hanselmann
  'version': (ShowClusterVersion, ARGS_NONE, [DEBUG_OPT],
662 9a033156 Iustin Pop
              "", "Shows the cluster version"),
663 4a265c08 Michael Hanselmann
  'getmaster': (ShowClusterMaster, ARGS_NONE, [DEBUG_OPT],
664 9a033156 Iustin Pop
                "", "Shows the cluster master"),
665 a8005e17 Michael Hanselmann
  'copyfile': (ClusterCopyFile, [ArgFile(min=1, max=1)],
666 7edc4637 Iustin Pop
               [DEBUG_OPT, NODE_LIST_OPT],
667 9a033156 Iustin Pop
               "[-n node...] <filename>",
668 a8083063 Iustin Pop
               "Copies a file to all (or only some) nodes"),
669 7edc4637 Iustin Pop
  'command': (RunClusterCommand, [ArgCommand(min=1)],
670 7edc4637 Iustin Pop
              [DEBUG_OPT, NODE_LIST_OPT],
671 9a033156 Iustin Pop
              "[-n node...] <command>",
672 a8083063 Iustin Pop
              "Runs a command on all (or only some) nodes"),
673 4a265c08 Michael Hanselmann
  'info': (ShowClusterConfig, ARGS_NONE, [DEBUG_OPT],
674 a8005e17 Michael Hanselmann
           "", "Show cluster configuration"),
675 4a265c08 Michael Hanselmann
  'list-tags': (ListTags, ARGS_NONE,
676 9a033156 Iustin Pop
                [DEBUG_OPT], "", "List the tags of the cluster"),
677 a8005e17 Michael Hanselmann
  'add-tags': (AddTags, [ArgUnknown()], [DEBUG_OPT, TAG_SRC_OPT],
678 9a033156 Iustin Pop
               "tag...", "Add tags to the cluster"),
679 a8005e17 Michael Hanselmann
  'remove-tags': (RemoveTags, [ArgUnknown()], [DEBUG_OPT, TAG_SRC_OPT],
680 9a033156 Iustin Pop
                  "tag...", "Remove tags from the cluster"),
681 a8005e17 Michael Hanselmann
  'search-tags': (SearchTags, [ArgUnknown(min=1, max=1)],
682 9a033156 Iustin Pop
                  [DEBUG_OPT], "", "Searches the tags on all objects on"
683 73415719 Iustin Pop
                  " the cluster for a given pattern (regex)"),
684 a8005e17 Michael Hanselmann
  'queue': (QueueOps,
685 a8005e17 Michael Hanselmann
            [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
686 a8005e17 Michael Hanselmann
            [DEBUG_OPT],
687 3ccafd0e Iustin Pop
            "drain|undrain|info", "Change queue properties"),
688 95b2e626 Michael Hanselmann
  'watcher': (WatcherOps,
689 95b2e626 Michael Hanselmann
              [ArgChoice(min=1, max=1,
690 95b2e626 Michael Hanselmann
                         choices=["pause", "continue", "info"]),
691 95b2e626 Michael Hanselmann
               ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
692 95b2e626 Michael Hanselmann
              [DEBUG_OPT],
693 95b2e626 Michael Hanselmann
              "{pause <timespec>|continue|info}", "Change watcher properties"),
694 4a265c08 Michael Hanselmann
  'modify': (SetClusterParams, ARGS_NONE,
695 b58726e8 Iustin Pop
             [DEBUG_OPT, BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT,
696 b58726e8 Iustin Pop
              NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT],
697 90b6aa3a Manuel Franceschini
             "[opts...]",
698 90b6aa3a Manuel Franceschini
             "Alters the parameters of the cluster"),
699 a8083063 Iustin Pop
  }
700 a8083063 Iustin Pop
701 a8083063 Iustin Pop
if __name__ == '__main__':
702 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))