Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ debac808

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