Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ 9b94905f

History | View | Annotate | Download (19.9 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 b3989551 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename)
284 b3989551 Iustin Pop
285 56bece1f Iustin Pop
  cl = GetClient()
286 56bece1f Iustin Pop
287 b3989551 Iustin Pop
  myname = utils.HostInfo().name
288 b3989551 Iustin Pop
289 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
290 56bece1f Iustin Pop
291 4040a784 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl)
292 4040a784 Iustin Pop
  results = [name for name in results if name != myname]
293 e00ea635 Michael Hanselmann
294 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
295 b3989551 Iustin Pop
  for node in results:
296 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
297 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
298 b3989551 Iustin Pop
299 a8083063 Iustin Pop
  return 0
300 a8083063 Iustin Pop
301 a8083063 Iustin Pop
302 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
303 a8083063 Iustin Pop
  """Run a command on some nodes.
304 a8083063 Iustin Pop
305 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
306 469ee405 Iustin Pop
  @type args: list
307 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
308 469ee405 Iustin Pop
  @rtype: int
309 469ee405 Iustin Pop
  @return: the desired exit code
310 a8083063 Iustin Pop
311 a8083063 Iustin Pop
  """
312 56bece1f Iustin Pop
  cl = GetClient()
313 7688d0d3 Michael Hanselmann
314 a8083063 Iustin Pop
  command = " ".join(args)
315 4040a784 Iustin Pop
316 4040a784 Iustin Pop
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl)
317 56bece1f Iustin Pop
318 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
319 56bece1f Iustin Pop
                                                    "master_node"])
320 b3989551 Iustin Pop
321 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
322 b3989551 Iustin Pop
323 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
324 b3989551 Iustin Pop
  if master_node in nodes:
325 b3989551 Iustin Pop
    nodes.remove(master_node)
326 b3989551 Iustin Pop
    nodes.append(master_node)
327 b3989551 Iustin Pop
328 b3989551 Iustin Pop
  for name in nodes:
329 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
330 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
331 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
332 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
333 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
334 b3989551 Iustin Pop
335 b3989551 Iustin Pop
  return 0
336 a8083063 Iustin Pop
337 a8083063 Iustin Pop
338 a8083063 Iustin Pop
def VerifyCluster(opts, args):
339 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
340 a8083063 Iustin Pop
341 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
342 469ee405 Iustin Pop
  @type args: list
343 469ee405 Iustin Pop
  @param args: should be an empty list
344 469ee405 Iustin Pop
  @rtype: int
345 469ee405 Iustin Pop
  @return: the desired exit code
346 a8083063 Iustin Pop
347 a8083063 Iustin Pop
  """
348 8d59409f Iustin Pop
  skip_checks = []
349 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
350 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
351 7c874ee1 Iustin Pop
  op = opcodes.OpVerifyCluster(skip_checks=skip_checks,
352 7c874ee1 Iustin Pop
                               verbose=opts.verbose,
353 a0c9776a Iustin Pop
                               error_codes=opts.error_codes,
354 a0c9776a Iustin Pop
                               debug_simulate_errors=opts.simulate_errors)
355 34290825 Michael Hanselmann
  if SubmitOpCode(op):
356 34290825 Michael Hanselmann
    return 0
357 34290825 Michael Hanselmann
  else:
358 34290825 Michael Hanselmann
    return 1
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
361 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
362 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
363 f4d4e184 Iustin Pop
364 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
365 469ee405 Iustin Pop
  @type args: list
366 469ee405 Iustin Pop
  @param args: should be an empty list
367 469ee405 Iustin Pop
  @rtype: int
368 469ee405 Iustin Pop
  @return: the desired exit code
369 f4d4e184 Iustin Pop
370 f4d4e184 Iustin Pop
  """
371 f4d4e184 Iustin Pop
  op = opcodes.OpVerifyDisks()
372 f4d4e184 Iustin Pop
  result = SubmitOpCode(op)
373 29d376ec Iustin Pop
  if not isinstance(result, (list, tuple)) or len(result) != 3:
374 f4d4e184 Iustin Pop
    raise errors.ProgrammerError("Unknown result type for OpVerifyDisks")
375 f4d4e184 Iustin Pop
376 29d376ec Iustin Pop
  bad_nodes, instances, missing = result
377 b63ed789 Iustin Pop
378 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
379 b63ed789 Iustin Pop
380 29d376ec Iustin Pop
  if bad_nodes:
381 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
382 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
383 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
384 b63ed789 Iustin Pop
      retcode |= 1
385 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
386 b63ed789 Iustin Pop
387 f4d4e184 Iustin Pop
  if instances:
388 f4d4e184 Iustin Pop
    for iname in instances:
389 b63ed789 Iustin Pop
      if iname in missing:
390 b63ed789 Iustin Pop
        continue
391 f4d4e184 Iustin Pop
      op = opcodes.OpActivateInstanceDisks(instance_name=iname)
392 f4d4e184 Iustin Pop
      try:
393 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
394 f4d4e184 Iustin Pop
        SubmitOpCode(op)
395 f4d4e184 Iustin Pop
      except errors.GenericError, err:
396 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
397 f4d4e184 Iustin Pop
        retcode |= nret
398 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
399 b63ed789 Iustin Pop
400 b63ed789 Iustin Pop
  if missing:
401 b63ed789 Iustin Pop
    for iname, ival in missing.iteritems():
402 29d376ec Iustin Pop
      all_missing = utils.all(ival, lambda x: x[0] in bad_nodes)
403 b63ed789 Iustin Pop
      if all_missing:
404 3a24c527 Iustin Pop
        ToStdout("Instance %s cannot be verified as it lives on"
405 3a24c527 Iustin Pop
                 " broken nodes", iname)
406 b63ed789 Iustin Pop
      else:
407 3a24c527 Iustin Pop
        ToStdout("Instance %s has missing logical volumes:", iname)
408 b63ed789 Iustin Pop
        ival.sort()
409 b63ed789 Iustin Pop
        for node, vol in ival:
410 29d376ec Iustin Pop
          if node in bad_nodes:
411 3a24c527 Iustin Pop
            ToStdout("\tbroken node %s /dev/xenvg/%s", node, vol)
412 b63ed789 Iustin Pop
          else:
413 3a24c527 Iustin Pop
            ToStdout("\t%s /dev/xenvg/%s", node, vol)
414 3a24c527 Iustin Pop
    ToStdout("You need to run replace_disks for all the above"
415 b63ed789 Iustin Pop
           " instances, if this message persist after fixing nodes.")
416 b63ed789 Iustin Pop
    retcode |= 1
417 f4d4e184 Iustin Pop
418 f4d4e184 Iustin Pop
  return retcode
419 f4d4e184 Iustin Pop
420 f4d4e184 Iustin Pop
421 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
422 60975797 Iustin Pop
  """Verify sizes of cluster disks.
423 60975797 Iustin Pop
424 60975797 Iustin Pop
  @param opts: the command line options selected by the user
425 60975797 Iustin Pop
  @type args: list
426 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
427 60975797 Iustin Pop
  @rtype: int
428 60975797 Iustin Pop
  @return: the desired exit code
429 60975797 Iustin Pop
430 60975797 Iustin Pop
  """
431 60975797 Iustin Pop
  op = opcodes.OpRepairDiskSizes(instances=args)
432 60975797 Iustin Pop
  SubmitOpCode(op)
433 60975797 Iustin Pop
434 60975797 Iustin Pop
435 4331f6cd Michael Hanselmann
@UsesRPC
436 a8083063 Iustin Pop
def MasterFailover(opts, args):
437 a8083063 Iustin Pop
  """Failover the master node.
438 a8083063 Iustin Pop
439 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
440 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
441 a8083063 Iustin Pop
  master.
442 a8083063 Iustin Pop
443 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
444 469ee405 Iustin Pop
  @type args: list
445 469ee405 Iustin Pop
  @param args: should be an empty list
446 469ee405 Iustin Pop
  @rtype: int
447 469ee405 Iustin Pop
  @return: the desired exit code
448 469ee405 Iustin Pop
449 a8083063 Iustin Pop
  """
450 8e2524c3 Guido Trotter
  if opts.no_voting:
451 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
452 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
453 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
454 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
455 8e2524c3 Guido Trotter
    if not AskUser(usertext):
456 8e2524c3 Guido Trotter
      return 1
457 8e2524c3 Guido Trotter
458 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
459 a8083063 Iustin Pop
460 a8083063 Iustin Pop
461 73415719 Iustin Pop
def SearchTags(opts, args):
462 73415719 Iustin Pop
  """Searches the tags on all the cluster.
463 73415719 Iustin Pop
464 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
465 469ee405 Iustin Pop
  @type args: list
466 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
467 469ee405 Iustin Pop
  @rtype: int
468 469ee405 Iustin Pop
  @return: the desired exit code
469 469ee405 Iustin Pop
470 73415719 Iustin Pop
  """
471 73415719 Iustin Pop
  op = opcodes.OpSearchTags(pattern=args[0])
472 73415719 Iustin Pop
  result = SubmitOpCode(op)
473 73415719 Iustin Pop
  if not result:
474 73415719 Iustin Pop
    return 1
475 73415719 Iustin Pop
  result = list(result)
476 73415719 Iustin Pop
  result.sort()
477 73415719 Iustin Pop
  for path, tag in result:
478 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
479 73415719 Iustin Pop
480 73415719 Iustin Pop
481 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
482 90b6aa3a Manuel Franceschini
  """Modify the cluster.
483 90b6aa3a Manuel Franceschini
484 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
485 469ee405 Iustin Pop
  @type args: list
486 469ee405 Iustin Pop
  @param args: should be an empty list
487 469ee405 Iustin Pop
  @rtype: int
488 469ee405 Iustin Pop
  @return: the desired exit code
489 90b6aa3a Manuel Franceschini
490 90b6aa3a Manuel Franceschini
  """
491 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
492 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
493 5af3da74 Guido Trotter
          opts.beparams or opts.nicparams or
494 5af3da74 Guido Trotter
          opts.candidate_pool_size is not None):
495 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
496 90b6aa3a Manuel Franceschini
    return 1
497 90b6aa3a Manuel Franceschini
498 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
499 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
500 3a24c527 Iustin Pop
    ToStdout("Options --no-lvm-storage and --vg-name conflict.")
501 90b6aa3a Manuel Franceschini
    return 1
502 b8a8fbe1 Guido Trotter
  elif not opts.lvm_storage:
503 b8a8fbe1 Guido Trotter
    vg_name = ''
504 90b6aa3a Manuel Franceschini
505 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
506 779c15bb Iustin Pop
  if hvlist is not None:
507 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
508 779c15bb Iustin Pop
509 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
510 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
511 a5728081 Guido Trotter
  for hv, hv_params in hvparams.iteritems():
512 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
513 779c15bb Iustin Pop
514 779c15bb Iustin Pop
  beparams = opts.beparams
515 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
516 779c15bb Iustin Pop
517 5af3da74 Guido Trotter
  nicparams = opts.nicparams
518 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
519 5af3da74 Guido Trotter
520 b8a8fbe1 Guido Trotter
  op = opcodes.OpSetClusterParams(vg_name=vg_name,
521 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
522 779c15bb Iustin Pop
                                  hvparams=hvparams,
523 4b7735f9 Iustin Pop
                                  beparams=beparams,
524 5af3da74 Guido Trotter
                                  nicparams=nicparams,
525 4b7735f9 Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size)
526 90b6aa3a Manuel Franceschini
  SubmitOpCode(op)
527 90b6aa3a Manuel Franceschini
  return 0
528 90b6aa3a Manuel Franceschini
529 90b6aa3a Manuel Franceschini
530 3ccafd0e Iustin Pop
def QueueOps(opts, args):
531 3ccafd0e Iustin Pop
  """Queue operations.
532 3ccafd0e Iustin Pop
533 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
534 469ee405 Iustin Pop
  @type args: list
535 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
536 469ee405 Iustin Pop
  @rtype: int
537 469ee405 Iustin Pop
  @return: the desired exit code
538 469ee405 Iustin Pop
539 3ccafd0e Iustin Pop
  """
540 3ccafd0e Iustin Pop
  command = args[0]
541 3ccafd0e Iustin Pop
  client = GetClient()
542 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
543 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
544 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
545 3ccafd0e Iustin Pop
  elif command == "info":
546 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
547 3ccafd0e Iustin Pop
    if result[0]:
548 3a24c527 Iustin Pop
      val = "set"
549 3ccafd0e Iustin Pop
    else:
550 3a24c527 Iustin Pop
      val = "unset"
551 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
552 2e668b38 Guido Trotter
  else:
553 2e668b38 Guido Trotter
    raise errors.OpPrereqError("Command '%s' is not valid." % command)
554 2e668b38 Guido Trotter
555 3ccafd0e Iustin Pop
  return 0
556 3ccafd0e Iustin Pop
557 95b2e626 Michael Hanselmann
558 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
559 28b498cd Michael Hanselmann
  if until is None or until < time.time():
560 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
561 28b498cd Michael Hanselmann
  else:
562 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
563 28b498cd Michael Hanselmann
564 28b498cd Michael Hanselmann
565 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
566 95b2e626 Michael Hanselmann
  """Watcher operations.
567 95b2e626 Michael Hanselmann
568 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
569 95b2e626 Michael Hanselmann
  @type args: list
570 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
571 95b2e626 Michael Hanselmann
  @rtype: int
572 95b2e626 Michael Hanselmann
  @return: the desired exit code
573 95b2e626 Michael Hanselmann
574 95b2e626 Michael Hanselmann
  """
575 95b2e626 Michael Hanselmann
  command = args[0]
576 95b2e626 Michael Hanselmann
  client = GetClient()
577 95b2e626 Michael Hanselmann
578 95b2e626 Michael Hanselmann
  if command == "continue":
579 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
580 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
581 95b2e626 Michael Hanselmann
582 95b2e626 Michael Hanselmann
  elif command == "pause":
583 95b2e626 Michael Hanselmann
    if len(args) < 2:
584 95b2e626 Michael Hanselmann
      raise errors.OpPrereqError("Missing pause duration")
585 95b2e626 Michael Hanselmann
586 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
587 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
588 95b2e626 Michael Hanselmann
589 95b2e626 Michael Hanselmann
  elif command == "info":
590 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
591 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
592 95b2e626 Michael Hanselmann
593 95b2e626 Michael Hanselmann
  else:
594 95b2e626 Michael Hanselmann
    raise errors.OpPrereqError("Command '%s' is not valid." % command)
595 95b2e626 Michael Hanselmann
596 95b2e626 Michael Hanselmann
  return 0
597 95b2e626 Michael Hanselmann
598 95b2e626 Michael Hanselmann
599 a8083063 Iustin Pop
commands = {
600 6ea815cf Iustin Pop
  'init': (
601 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
602 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
603 6ea815cf Iustin Pop
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
604 b989b9d9 Ken Wehr
     NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
605 b989b9d9 Ken Wehr
     SECONDARY_IP_OPT, VG_NAME_OPT],
606 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
607 6ea815cf Iustin Pop
  'destroy': (
608 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
609 6ea815cf Iustin Pop
    "", "Destroy cluster"),
610 6ea815cf Iustin Pop
  'rename': (
611 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
612 064c21f8 Iustin Pop
    [FORCE_OPT],
613 6ea815cf Iustin Pop
    "<new_name>",
614 6ea815cf Iustin Pop
    "Renames the cluster"),
615 6ea815cf Iustin Pop
  'redist-conf': (
616 064c21f8 Iustin Pop
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT],
617 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
618 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
619 6ea815cf Iustin Pop
  'verify': (
620 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
621 064c21f8 Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT],
622 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
623 6ea815cf Iustin Pop
  'verify-disks': (
624 064c21f8 Iustin Pop
    VerifyDisks, ARGS_NONE, [],
625 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
626 6ea815cf Iustin Pop
  'repair-disk-sizes': (
627 064c21f8 Iustin Pop
    RepairDiskSizes, ARGS_MANY_INSTANCES, [],
628 6ea815cf Iustin Pop
    "", "Updates mismatches in recorded disk sizes"),
629 6ea815cf Iustin Pop
  'masterfailover': (
630 064c21f8 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT],
631 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
632 6ea815cf Iustin Pop
  'version': (
633 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
634 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
635 6ea815cf Iustin Pop
  'getmaster': (
636 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
637 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
638 6ea815cf Iustin Pop
  'copyfile': (
639 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
640 064c21f8 Iustin Pop
    [NODE_LIST_OPT],
641 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
642 6ea815cf Iustin Pop
  'command': (
643 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
644 064c21f8 Iustin Pop
    [NODE_LIST_OPT],
645 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
646 6ea815cf Iustin Pop
  'info': (
647 064c21f8 Iustin Pop
    ShowClusterConfig, ARGS_NONE, [],
648 6ea815cf Iustin Pop
    "", "Show cluster configuration"),
649 6ea815cf Iustin Pop
  'list-tags': (
650 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
651 6ea815cf Iustin Pop
  'add-tags': (
652 064c21f8 Iustin Pop
    AddTags, [ArgUnknown()], [TAG_SRC_OPT],
653 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
654 6ea815cf Iustin Pop
  'remove-tags': (
655 064c21f8 Iustin Pop
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT],
656 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
657 6ea815cf Iustin Pop
  'search-tags': (
658 6ea815cf Iustin Pop
    SearchTags, [ArgUnknown(min=1, max=1)],
659 064c21f8 Iustin Pop
    [], "", "Searches the tags on all objects on"
660 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
661 6ea815cf Iustin Pop
  'queue': (
662 6ea815cf Iustin Pop
    QueueOps,
663 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
664 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
665 6ea815cf Iustin Pop
  'watcher': (
666 6ea815cf Iustin Pop
    WatcherOps,
667 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
668 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
669 064c21f8 Iustin Pop
    [],
670 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
671 6ea815cf Iustin Pop
  'modify': (
672 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
673 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT,
674 6ea815cf Iustin Pop
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT],
675 6ea815cf Iustin Pop
    "[opts...]",
676 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
677 a8083063 Iustin Pop
  }
678 a8083063 Iustin Pop
679 a8083063 Iustin Pop
if __name__ == '__main__':
680 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))