Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ 23683c26

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