Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ 19b9ba9a

History | View | Annotate | Download (29.1 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 db5a8a2d Iustin Pop
# Copyright (C) 2006, 2007, 2010 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 7260cfbe Iustin Pop
"""Cluster related commands"""
22 a8083063 Iustin Pop
23 2d54e29c Iustin Pop
# pylint: disable-msg=W0401,W0613,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2d54e29c Iustin Pop
# W0613: Unused argument, since all functions follow the same API
26 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
27 7260cfbe Iustin Pop
# C0103: Invalid name gnt-cluster
28 2f79bd34 Iustin Pop
29 a8083063 Iustin Pop
import sys
30 b3989551 Iustin Pop
import os.path
31 95b2e626 Michael Hanselmann
import time
32 6d4a1656 Michael Hanselmann
import OpenSSL
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti.cli import *
35 a8083063 Iustin Pop
from ganeti import opcodes
36 c2a62a33 Michael Hanselmann
from ganeti import constants
37 f4d4e184 Iustin Pop
from ganeti import errors
38 b63ed789 Iustin Pop
from ganeti import utils
39 a0c9f010 Michael Hanselmann
from ganeti import bootstrap
40 b3989551 Iustin Pop
from ganeti import ssh
41 d3cfe525 Guido Trotter
from ganeti import objects
42 1338f2b4 Balazs Lecz
from ganeti import uidpool
43 cea881e5 Michael Hanselmann
from ganeti import compat
44 a8083063 Iustin Pop
45 a8083063 Iustin Pop
46 4331f6cd Michael Hanselmann
@UsesRPC
47 a8083063 Iustin Pop
def InitCluster(opts, args):
48 a8083063 Iustin Pop
  """Initialize the cluster.
49 a8083063 Iustin Pop
50 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
51 469ee405 Iustin Pop
  @type args: list
52 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
53 469ee405 Iustin Pop
      cluster name
54 469ee405 Iustin Pop
  @rtype: int
55 469ee405 Iustin Pop
  @return: the desired exit code
56 a8083063 Iustin Pop
57 a8083063 Iustin Pop
  """
58 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
59 3a24c527 Iustin Pop
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
60 90b6aa3a Manuel Franceschini
    return 1
61 90b6aa3a Manuel Franceschini
62 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
63 90b6aa3a Manuel Franceschini
  if opts.lvm_storage and not opts.vg_name:
64 90b6aa3a Manuel Franceschini
    vg_name = constants.DEFAULT_VG
65 90b6aa3a Manuel Franceschini
66 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
67 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
68 ed14ed48 Luca Bigliardi
    return 1
69 ed14ed48 Luca Bigliardi
70 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
71 ed14ed48 Luca Bigliardi
  if opts.drbd_storage and not opts.drbd_helper:
72 ed14ed48 Luca Bigliardi
    drbd_helper = constants.DEFAULT_DRBD_HELPER
73 ed14ed48 Luca Bigliardi
74 ea3a925f Alexander Schreiber
  hvlist = opts.enabled_hypervisors
75 383a3591 Iustin Pop
  if hvlist is None:
76 383a3591 Iustin Pop
    hvlist = constants.DEFAULT_ENABLED_HYPERVISOR
77 066f465d Guido Trotter
  hvlist = hvlist.split(",")
78 ea3a925f Alexander Schreiber
79 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
80 ea3a925f Alexander Schreiber
  beparams = opts.beparams
81 b6a30b0d Guido Trotter
  nicparams = opts.nicparams
82 ea3a925f Alexander Schreiber
83 ea3a925f Alexander Schreiber
  # prepare beparams dict
84 d3cfe525 Guido Trotter
  beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams)
85 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
86 ea3a925f Alexander Schreiber
87 b6a30b0d Guido Trotter
  # prepare nicparams dict
88 b6a30b0d Guido Trotter
  nicparams = objects.FillDict(constants.NICC_DEFAULTS, nicparams)
89 b6a30b0d Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
90 b6a30b0d Guido Trotter
91 ea3a925f Alexander Schreiber
  # prepare hvparams dict
92 ea3a925f Alexander Schreiber
  for hv in constants.HYPER_TYPES:
93 ea3a925f Alexander Schreiber
    if hv not in hvparams:
94 ea3a925f Alexander Schreiber
      hvparams[hv] = {}
95 d3cfe525 Guido Trotter
    hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv])
96 a5728081 Guido Trotter
    utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES)
97 ea3a925f Alexander Schreiber
98 e32df528 Iustin Pop
  if opts.candidate_pool_size is None:
99 e32df528 Iustin Pop
    opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT
100 e32df528 Iustin Pop
101 e3646f22 Iustin Pop
  if opts.mac_prefix is None:
102 e3646f22 Iustin Pop
    opts.mac_prefix = constants.DEFAULT_MAC_PREFIX
103 e3646f22 Iustin Pop
104 39b0f0c2 Balazs Lecz
  uid_pool = opts.uid_pool
105 39b0f0c2 Balazs Lecz
  if uid_pool is not None:
106 39b0f0c2 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
107 39b0f0c2 Balazs Lecz
108 a0c9f010 Michael Hanselmann
  bootstrap.InitCluster(cluster_name=args[0],
109 a0c9f010 Michael Hanselmann
                        secondary_ip=opts.secondary_ip,
110 a0c9f010 Michael Hanselmann
                        vg_name=vg_name,
111 a0c9f010 Michael Hanselmann
                        mac_prefix=opts.mac_prefix,
112 a0c9f010 Michael Hanselmann
                        master_netdev=opts.master_netdev,
113 ea3a925f Alexander Schreiber
                        file_storage_dir=opts.file_storage_dir,
114 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
115 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
116 ce735215 Guido Trotter
                        beparams=beparams,
117 b6a30b0d Guido Trotter
                        nicparams=nicparams,
118 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
119 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
120 b989b9d9 Ken Wehr
                        modify_ssh_setup=opts.modify_ssh_setup,
121 3953242f Iustin Pop
                        maintain_node_health=opts.maintain_node_health,
122 ed14ed48 Luca Bigliardi
                        drbd_helper=drbd_helper,
123 39b0f0c2 Balazs Lecz
                        uid_pool=uid_pool,
124 bf4af505 Apollon Oikonomopoulos
                        default_iallocator=opts.default_iallocator,
125 ce735215 Guido Trotter
                        )
126 3552cd2e Luca Bigliardi
  op = opcodes.OpPostInitCluster()
127 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
128 a8083063 Iustin Pop
  return 0
129 a8083063 Iustin Pop
130 a8083063 Iustin Pop
131 4331f6cd Michael Hanselmann
@UsesRPC
132 a8083063 Iustin Pop
def DestroyCluster(opts, args):
133 a8083063 Iustin Pop
  """Destroy the cluster.
134 a8083063 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 be an empty list
138 469ee405 Iustin Pop
  @rtype: int
139 469ee405 Iustin Pop
  @return: the desired exit code
140 098c0958 Michael Hanselmann
141 a8083063 Iustin Pop
  """
142 a8083063 Iustin Pop
  if not opts.yes_do_it:
143 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
144 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
145 a8083063 Iustin Pop
    return 1
146 a8083063 Iustin Pop
147 a8083063 Iustin Pop
  op = opcodes.OpDestroyCluster()
148 400ca2f7 Iustin Pop
  master = SubmitOpCode(op, opts=opts)
149 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
150 140aa4a8 Iustin Pop
  # shutdown all the daemons
151 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
152 a8083063 Iustin Pop
  return 0
153 a8083063 Iustin Pop
154 a8083063 Iustin Pop
155 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
156 07bd8a51 Iustin Pop
  """Rename the cluster.
157 07bd8a51 Iustin Pop
158 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
159 469ee405 Iustin Pop
  @type args: list
160 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
161 469ee405 Iustin Pop
  @rtype: int
162 469ee405 Iustin Pop
  @return: the desired exit code
163 07bd8a51 Iustin Pop
164 07bd8a51 Iustin Pop
  """
165 6a016df9 Michael Hanselmann
  cl = GetClient()
166 6a016df9 Michael Hanselmann
167 6a016df9 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
168 6a016df9 Michael Hanselmann
169 6a016df9 Michael Hanselmann
  new_name = args[0]
170 07bd8a51 Iustin Pop
  if not opts.force:
171 6a016df9 Michael Hanselmann
    usertext = ("This will rename the cluster from '%s' to '%s'. If you are"
172 6a016df9 Michael Hanselmann
                " connected over the network to the cluster name, the"
173 6a016df9 Michael Hanselmann
                " operation is very dangerous as the IP address will be"
174 6a016df9 Michael Hanselmann
                " removed from the node and the change may not go through."
175 6a016df9 Michael Hanselmann
                " Continue?") % (cluster_name, new_name)
176 47988778 Iustin Pop
    if not AskUser(usertext):
177 07bd8a51 Iustin Pop
      return 1
178 07bd8a51 Iustin Pop
179 6a016df9 Michael Hanselmann
  op = opcodes.OpRenameCluster(name=new_name)
180 6a016df9 Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
181 6a016df9 Michael Hanselmann
182 48418fea Iustin Pop
  if result:
183 48418fea Iustin Pop
    ToStdout("Cluster renamed from '%s' to '%s'", cluster_name, result)
184 6a016df9 Michael Hanselmann
185 07bd8a51 Iustin Pop
  return 0
186 07bd8a51 Iustin Pop
187 07bd8a51 Iustin Pop
188 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
189 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
190 afee0879 Iustin Pop
191 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
192 afee0879 Iustin Pop
  @type args: list
193 afee0879 Iustin Pop
  @param args: empty list
194 afee0879 Iustin Pop
  @rtype: int
195 afee0879 Iustin Pop
  @return: the desired exit code
196 afee0879 Iustin Pop
197 afee0879 Iustin Pop
  """
198 81a49123 Iustin Pop
  op = opcodes.OpRedistributeConfig()
199 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
200 afee0879 Iustin Pop
  return 0
201 afee0879 Iustin Pop
202 afee0879 Iustin Pop
203 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
204 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
205 a8083063 Iustin Pop
206 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
207 469ee405 Iustin Pop
  @type args: list
208 469ee405 Iustin Pop
  @param args: should be an empty list
209 469ee405 Iustin Pop
  @rtype: int
210 469ee405 Iustin Pop
  @return: the desired exit code
211 a8083063 Iustin Pop
212 a8083063 Iustin Pop
  """
213 2e7b8369 Iustin Pop
  cl = GetClient()
214 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
215 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
216 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
217 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
218 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
219 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
220 a8083063 Iustin Pop
  return 0
221 a8083063 Iustin Pop
222 a8083063 Iustin Pop
223 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
224 a8083063 Iustin Pop
  """Write name of master node to the standard output.
225 a8083063 Iustin Pop
226 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
227 469ee405 Iustin Pop
  @type args: list
228 469ee405 Iustin Pop
  @param args: should be an empty list
229 469ee405 Iustin Pop
  @rtype: int
230 469ee405 Iustin Pop
  @return: the desired exit code
231 a8083063 Iustin Pop
232 a8083063 Iustin Pop
  """
233 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
234 8eb148ae Iustin Pop
  ToStdout(master)
235 a8083063 Iustin Pop
  return 0
236 a8083063 Iustin Pop
237 cac599f1 Michael Hanselmann
238 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
239 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
240 1094acda Guido Trotter
241 1094acda Guido Trotter
  @type paramsdict: dict of dicts
242 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
243 664a9d73 René Nussbaumer
  @type level: int
244 664a9d73 René Nussbaumer
  @param level: Level of indention
245 1094acda Guido Trotter
246 1094acda Guido Trotter
  """
247 664a9d73 René Nussbaumer
  indent = "  " * level
248 9d91c6ab Guido Trotter
  for item, val in sorted(paramsdict.items()):
249 664a9d73 René Nussbaumer
    if isinstance(val, dict):
250 664a9d73 René Nussbaumer
      ToStdout("%s- %s:", indent, item)
251 d729e03a Guido Trotter
      _PrintGroupedParams(val, level=level + 1, roman=roman)
252 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
253 d729e03a Guido Trotter
      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
254 664a9d73 René Nussbaumer
    else:
255 664a9d73 René Nussbaumer
      ToStdout("%s  %s: %s", indent, item, val)
256 a8083063 Iustin Pop
257 cac599f1 Michael Hanselmann
258 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
259 a8083063 Iustin Pop
  """Shows cluster information.
260 a8083063 Iustin Pop
261 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
262 469ee405 Iustin Pop
  @type args: list
263 469ee405 Iustin Pop
  @param args: should be an empty list
264 469ee405 Iustin Pop
  @rtype: int
265 469ee405 Iustin Pop
  @return: the desired exit code
266 469ee405 Iustin Pop
267 a8083063 Iustin Pop
  """
268 2e7b8369 Iustin Pop
  cl = GetClient()
269 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
270 a8083063 Iustin Pop
271 3a24c527 Iustin Pop
  ToStdout("Cluster name: %s", result["name"])
272 259578eb Iustin Pop
  ToStdout("Cluster UUID: %s", result["uuid"])
273 a8083063 Iustin Pop
274 90f72445 Iustin Pop
  ToStdout("Creation time: %s", utils.FormatTime(result["ctime"]))
275 90f72445 Iustin Pop
  ToStdout("Modification time: %s", utils.FormatTime(result["mtime"]))
276 90f72445 Iustin Pop
277 3a24c527 Iustin Pop
  ToStdout("Master node: %s", result["master"])
278 a8083063 Iustin Pop
279 3a24c527 Iustin Pop
  ToStdout("Architecture (this node): %s (%s)",
280 3a24c527 Iustin Pop
           result["architecture"][0], result["architecture"][1])
281 a8083063 Iustin Pop
282 c118d1f4 Michael Hanselmann
  if result["tags"]:
283 1f864b60 Iustin Pop
    tags = utils.CommaJoin(utils.NiceSort(result["tags"]))
284 c118d1f4 Michael Hanselmann
  else:
285 c118d1f4 Michael Hanselmann
    tags = "(none)"
286 c118d1f4 Michael Hanselmann
287 c118d1f4 Michael Hanselmann
  ToStdout("Tags: %s", tags)
288 c118d1f4 Michael Hanselmann
289 02691904 Alexander Schreiber
  ToStdout("Default hypervisor: %s", result["default_hypervisor"])
290 1f864b60 Iustin Pop
  ToStdout("Enabled hypervisors: %s",
291 1f864b60 Iustin Pop
           utils.CommaJoin(result["enabled_hypervisors"]))
292 469f88e1 Iustin Pop
293 3a24c527 Iustin Pop
  ToStdout("Hypervisor parameters:")
294 1094acda Guido Trotter
  _PrintGroupedParams(result["hvparams"])
295 469f88e1 Iustin Pop
296 dbb24ec7 Iustin Pop
  ToStdout("OS-specific hypervisor parameters:")
297 664a9d73 René Nussbaumer
  _PrintGroupedParams(result["os_hvp"])
298 664a9d73 René Nussbaumer
299 dbb24ec7 Iustin Pop
  ToStdout("OS parameters:")
300 dbb24ec7 Iustin Pop
  _PrintGroupedParams(result["osparams"])
301 dbb24ec7 Iustin Pop
302 3a24c527 Iustin Pop
  ToStdout("Cluster parameters:")
303 d729e03a Guido Trotter
  ToStdout("  - candidate pool size: %s",
304 d729e03a Guido Trotter
            compat.TryToRoman(result["candidate_pool_size"],
305 d729e03a Guido Trotter
                              convert=opts.roman_integers))
306 a8001106 Guido Trotter
  ToStdout("  - master netdev: %s", result["master_netdev"])
307 a8001106 Guido Trotter
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
308 5a3ab484 Iustin Pop
  if result["reserved_lvs"]:
309 5a3ab484 Iustin Pop
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
310 5a3ab484 Iustin Pop
  else:
311 5a3ab484 Iustin Pop
    reserved_lvs = "(none)"
312 5a3ab484 Iustin Pop
  ToStdout("  - lvm reserved volumes: %s", reserved_lvs)
313 ed14ed48 Luca Bigliardi
  ToStdout("  - drbd usermode helper: %s", result["drbd_usermode_helper"])
314 a8001106 Guido Trotter
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
315 3953242f Iustin Pop
  ToStdout("  - maintenance of node health: %s",
316 3953242f Iustin Pop
           result["maintain_node_health"])
317 d729e03a Guido Trotter
  ToStdout("  - uid pool: %s",
318 d729e03a Guido Trotter
            uidpool.FormatUidPool(result["uid_pool"],
319 d729e03a Guido Trotter
                                  roman=opts.roman_integers))
320 bf4af505 Apollon Oikonomopoulos
  ToStdout("  - default instance allocator: %s", result["default_iallocator"])
321 4b7735f9 Iustin Pop
322 4b7735f9 Iustin Pop
  ToStdout("Default instance parameters:")
323 d729e03a Guido Trotter
  _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
324 1094acda Guido Trotter
325 1094acda Guido Trotter
  ToStdout("Default nic parameters:")
326 d729e03a Guido Trotter
  _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers)
327 8a12ce45 Iustin Pop
328 a8083063 Iustin Pop
  return 0
329 a8083063 Iustin Pop
330 a8083063 Iustin Pop
331 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
332 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
333 a8083063 Iustin Pop
334 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
335 469ee405 Iustin Pop
  @type args: list
336 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
337 469ee405 Iustin Pop
      the file to be copied
338 469ee405 Iustin Pop
  @rtype: int
339 469ee405 Iustin Pop
  @return: the desired exit code
340 a8083063 Iustin Pop
341 a8083063 Iustin Pop
  """
342 b3989551 Iustin Pop
  filename = args[0]
343 b3989551 Iustin Pop
  if not os.path.exists(filename):
344 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
345 debac808 Iustin Pop
                               errors.ECODE_INVAL)
346 b3989551 Iustin Pop
347 56bece1f Iustin Pop
  cl = GetClient()
348 56bece1f Iustin Pop
349 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
350 56bece1f Iustin Pop
351 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
352 74adc100 Iustin Pop
                           secondary_ips=opts.use_replication_network)
353 e00ea635 Michael Hanselmann
354 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
355 b3989551 Iustin Pop
  for node in results:
356 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
357 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
358 b3989551 Iustin Pop
359 a8083063 Iustin Pop
  return 0
360 a8083063 Iustin Pop
361 a8083063 Iustin Pop
362 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
363 a8083063 Iustin Pop
  """Run a command on some nodes.
364 a8083063 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 contain the command to be run and its arguments
368 469ee405 Iustin Pop
  @rtype: int
369 469ee405 Iustin Pop
  @return: the desired exit code
370 a8083063 Iustin Pop
371 a8083063 Iustin Pop
  """
372 56bece1f Iustin Pop
  cl = GetClient()
373 7688d0d3 Michael Hanselmann
374 a8083063 Iustin Pop
  command = " ".join(args)
375 4040a784 Iustin Pop
376 4040a784 Iustin Pop
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl)
377 56bece1f Iustin Pop
378 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
379 56bece1f Iustin Pop
                                                    "master_node"])
380 b3989551 Iustin Pop
381 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
382 b3989551 Iustin Pop
383 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
384 b3989551 Iustin Pop
  if master_node in nodes:
385 b3989551 Iustin Pop
    nodes.remove(master_node)
386 b3989551 Iustin Pop
    nodes.append(master_node)
387 b3989551 Iustin Pop
388 b3989551 Iustin Pop
  for name in nodes:
389 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
390 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
391 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
392 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
393 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
394 b3989551 Iustin Pop
395 b3989551 Iustin Pop
  return 0
396 a8083063 Iustin Pop
397 a8083063 Iustin Pop
398 a8083063 Iustin Pop
def VerifyCluster(opts, args):
399 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
400 a8083063 Iustin Pop
401 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
402 469ee405 Iustin Pop
  @type args: list
403 469ee405 Iustin Pop
  @param args: should be an empty list
404 469ee405 Iustin Pop
  @rtype: int
405 469ee405 Iustin Pop
  @return: the desired exit code
406 a8083063 Iustin Pop
407 a8083063 Iustin Pop
  """
408 8d59409f Iustin Pop
  skip_checks = []
409 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
410 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
411 7c874ee1 Iustin Pop
  op = opcodes.OpVerifyCluster(skip_checks=skip_checks,
412 7c874ee1 Iustin Pop
                               verbose=opts.verbose,
413 a0c9776a Iustin Pop
                               error_codes=opts.error_codes,
414 a0c9776a Iustin Pop
                               debug_simulate_errors=opts.simulate_errors)
415 400ca2f7 Iustin Pop
  if SubmitOpCode(op, opts=opts):
416 34290825 Michael Hanselmann
    return 0
417 34290825 Michael Hanselmann
  else:
418 34290825 Michael Hanselmann
    return 1
419 a8083063 Iustin Pop
420 a8083063 Iustin Pop
421 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
422 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
423 f4d4e184 Iustin Pop
424 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
425 469ee405 Iustin Pop
  @type args: list
426 469ee405 Iustin Pop
  @param args: should be an empty list
427 469ee405 Iustin Pop
  @rtype: int
428 469ee405 Iustin Pop
  @return: the desired exit code
429 f4d4e184 Iustin Pop
430 f4d4e184 Iustin Pop
  """
431 f4d4e184 Iustin Pop
  op = opcodes.OpVerifyDisks()
432 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
433 29d376ec Iustin Pop
  if not isinstance(result, (list, tuple)) or len(result) != 3:
434 f4d4e184 Iustin Pop
    raise errors.ProgrammerError("Unknown result type for OpVerifyDisks")
435 f4d4e184 Iustin Pop
436 29d376ec Iustin Pop
  bad_nodes, instances, missing = result
437 b63ed789 Iustin Pop
438 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
439 b63ed789 Iustin Pop
440 29d376ec Iustin Pop
  if bad_nodes:
441 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
442 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
443 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
444 b63ed789 Iustin Pop
      retcode |= 1
445 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
446 b63ed789 Iustin Pop
447 f4d4e184 Iustin Pop
  if instances:
448 f4d4e184 Iustin Pop
    for iname in instances:
449 b63ed789 Iustin Pop
      if iname in missing:
450 b63ed789 Iustin Pop
        continue
451 f4d4e184 Iustin Pop
      op = opcodes.OpActivateInstanceDisks(instance_name=iname)
452 f4d4e184 Iustin Pop
      try:
453 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
454 400ca2f7 Iustin Pop
        SubmitOpCode(op, opts=opts)
455 f4d4e184 Iustin Pop
      except errors.GenericError, err:
456 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
457 f4d4e184 Iustin Pop
        retcode |= nret
458 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
459 b63ed789 Iustin Pop
460 b63ed789 Iustin Pop
  if missing:
461 b63ed789 Iustin Pop
    for iname, ival in missing.iteritems():
462 403f5172 Guido Trotter
      all_missing = compat.all(x[0] in bad_nodes for x in ival)
463 b63ed789 Iustin Pop
      if all_missing:
464 3a24c527 Iustin Pop
        ToStdout("Instance %s cannot be verified as it lives on"
465 3a24c527 Iustin Pop
                 " broken nodes", iname)
466 b63ed789 Iustin Pop
      else:
467 3a24c527 Iustin Pop
        ToStdout("Instance %s has missing logical volumes:", iname)
468 b63ed789 Iustin Pop
        ival.sort()
469 b63ed789 Iustin Pop
        for node, vol in ival:
470 29d376ec Iustin Pop
          if node in bad_nodes:
471 3a24c527 Iustin Pop
            ToStdout("\tbroken node %s /dev/xenvg/%s", node, vol)
472 b63ed789 Iustin Pop
          else:
473 3a24c527 Iustin Pop
            ToStdout("\t%s /dev/xenvg/%s", node, vol)
474 3a24c527 Iustin Pop
    ToStdout("You need to run replace_disks for all the above"
475 b63ed789 Iustin Pop
           " instances, if this message persist after fixing nodes.")
476 b63ed789 Iustin Pop
    retcode |= 1
477 f4d4e184 Iustin Pop
478 f4d4e184 Iustin Pop
  return retcode
479 f4d4e184 Iustin Pop
480 f4d4e184 Iustin Pop
481 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
482 60975797 Iustin Pop
  """Verify sizes of cluster disks.
483 60975797 Iustin Pop
484 60975797 Iustin Pop
  @param opts: the command line options selected by the user
485 60975797 Iustin Pop
  @type args: list
486 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
487 60975797 Iustin Pop
  @rtype: int
488 60975797 Iustin Pop
  @return: the desired exit code
489 60975797 Iustin Pop
490 60975797 Iustin Pop
  """
491 60975797 Iustin Pop
  op = opcodes.OpRepairDiskSizes(instances=args)
492 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
493 60975797 Iustin Pop
494 60975797 Iustin Pop
495 4331f6cd Michael Hanselmann
@UsesRPC
496 a8083063 Iustin Pop
def MasterFailover(opts, args):
497 a8083063 Iustin Pop
  """Failover the master node.
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
500 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
501 a8083063 Iustin Pop
  master.
502 a8083063 Iustin Pop
503 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
504 469ee405 Iustin Pop
  @type args: list
505 469ee405 Iustin Pop
  @param args: should be an empty list
506 469ee405 Iustin Pop
  @rtype: int
507 469ee405 Iustin Pop
  @return: the desired exit code
508 469ee405 Iustin Pop
509 a8083063 Iustin Pop
  """
510 8e2524c3 Guido Trotter
  if opts.no_voting:
511 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
512 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
513 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
514 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
515 8e2524c3 Guido Trotter
    if not AskUser(usertext):
516 8e2524c3 Guido Trotter
      return 1
517 8e2524c3 Guido Trotter
518 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
519 a8083063 Iustin Pop
520 a8083063 Iustin Pop
521 4404ffad Iustin Pop
def MasterPing(opts, args):
522 4404ffad Iustin Pop
  """Checks if the master is alive.
523 4404ffad Iustin Pop
524 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
525 4404ffad Iustin Pop
  @type args: list
526 4404ffad Iustin Pop
  @param args: should be an empty list
527 4404ffad Iustin Pop
  @rtype: int
528 4404ffad Iustin Pop
  @return: the desired exit code
529 4404ffad Iustin Pop
530 4404ffad Iustin Pop
  """
531 4404ffad Iustin Pop
  try:
532 4404ffad Iustin Pop
    cl = GetClient()
533 4404ffad Iustin Pop
    cl.QueryClusterInfo()
534 4404ffad Iustin Pop
    return 0
535 4404ffad Iustin Pop
  except Exception: # pylint: disable-msg=W0703
536 4404ffad Iustin Pop
    return 1
537 4404ffad Iustin Pop
538 4404ffad Iustin Pop
539 73415719 Iustin Pop
def SearchTags(opts, args):
540 73415719 Iustin Pop
  """Searches the tags on all the cluster.
541 73415719 Iustin Pop
542 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
543 469ee405 Iustin Pop
  @type args: list
544 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
545 469ee405 Iustin Pop
  @rtype: int
546 469ee405 Iustin Pop
  @return: the desired exit code
547 469ee405 Iustin Pop
548 73415719 Iustin Pop
  """
549 73415719 Iustin Pop
  op = opcodes.OpSearchTags(pattern=args[0])
550 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
551 73415719 Iustin Pop
  if not result:
552 73415719 Iustin Pop
    return 1
553 73415719 Iustin Pop
  result = list(result)
554 73415719 Iustin Pop
  result.sort()
555 73415719 Iustin Pop
  for path, tag in result:
556 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
557 73415719 Iustin Pop
558 73415719 Iustin Pop
559 6d4a1656 Michael Hanselmann
def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
560 3db3eb2a Michael Hanselmann
                 new_confd_hmac_key, new_cds, cds_filename,
561 3db3eb2a Michael Hanselmann
                 force):
562 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
563 6d4a1656 Michael Hanselmann
564 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
565 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
566 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
567 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
568 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
569 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
570 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
571 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
572 3db3eb2a Michael Hanselmann
  @type new_cds: bool
573 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
574 3db3eb2a Michael Hanselmann
  @type cds_filename: string
575 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
576 6d4a1656 Michael Hanselmann
  @type force: bool
577 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
578 6d4a1656 Michael Hanselmann
579 6d4a1656 Michael Hanselmann
  """
580 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
581 6d4a1656 Michael Hanselmann
    ToStderr("Only one of the --new-rapi-certficate and --rapi-certificate"
582 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
583 6d4a1656 Michael Hanselmann
    return 1
584 6d4a1656 Michael Hanselmann
585 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
586 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
587 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
588 3db3eb2a Michael Hanselmann
             " the same time.")
589 3db3eb2a Michael Hanselmann
    return 1
590 3db3eb2a Michael Hanselmann
591 6d4a1656 Michael Hanselmann
  if rapi_cert_filename:
592 6d4a1656 Michael Hanselmann
    # Read and verify new certificate
593 6d4a1656 Michael Hanselmann
    try:
594 6d4a1656 Michael Hanselmann
      rapi_cert_pem = utils.ReadFile(rapi_cert_filename)
595 6d4a1656 Michael Hanselmann
596 6d4a1656 Michael Hanselmann
      OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
597 6d4a1656 Michael Hanselmann
                                      rapi_cert_pem)
598 6d4a1656 Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
599 6d4a1656 Michael Hanselmann
      ToStderr("Can't load new RAPI certificate from %s: %s" %
600 6d4a1656 Michael Hanselmann
               (rapi_cert_filename, str(err)))
601 6d4a1656 Michael Hanselmann
      return 1
602 6d4a1656 Michael Hanselmann
603 6d4a1656 Michael Hanselmann
    try:
604 6d4a1656 Michael Hanselmann
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, rapi_cert_pem)
605 6d4a1656 Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
606 6d4a1656 Michael Hanselmann
      ToStderr("Can't load new RAPI private key from %s: %s" %
607 6d4a1656 Michael Hanselmann
               (rapi_cert_filename, str(err)))
608 6d4a1656 Michael Hanselmann
      return 1
609 6d4a1656 Michael Hanselmann
610 6d4a1656 Michael Hanselmann
  else:
611 6d4a1656 Michael Hanselmann
    rapi_cert_pem = None
612 6d4a1656 Michael Hanselmann
613 3db3eb2a Michael Hanselmann
  if cds_filename:
614 3db3eb2a Michael Hanselmann
    try:
615 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
616 3db3eb2a Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
617 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
618 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
619 3db3eb2a Michael Hanselmann
      return 1
620 3db3eb2a Michael Hanselmann
  else:
621 3db3eb2a Michael Hanselmann
    cds = None
622 3db3eb2a Michael Hanselmann
623 6d4a1656 Michael Hanselmann
  if not force:
624 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
625 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
626 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
627 6d4a1656 Michael Hanselmann
      return 1
628 6d4a1656 Michael Hanselmann
629 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
630 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
631 6d4a1656 Michael Hanselmann
    bootstrap.GenerateClusterCrypto(new_cluster_cert, new_rapi_cert,
632 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
633 3db3eb2a Michael Hanselmann
                                    new_cds,
634 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
635 3db3eb2a Michael Hanselmann
                                    cds=cds)
636 6d4a1656 Michael Hanselmann
637 6d4a1656 Michael Hanselmann
    files_to_copy = []
638 6d4a1656 Michael Hanselmann
639 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
640 168c1de2 Michael Hanselmann
      files_to_copy.append(constants.NODED_CERT_FILE)
641 6d4a1656 Michael Hanselmann
642 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
643 6d4a1656 Michael Hanselmann
      files_to_copy.append(constants.RAPI_CERT_FILE)
644 6d4a1656 Michael Hanselmann
645 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
646 6b7d5878 Michael Hanselmann
      files_to_copy.append(constants.CONFD_HMAC_KEY)
647 6d4a1656 Michael Hanselmann
648 3db3eb2a Michael Hanselmann
    if new_cds or cds:
649 3db3eb2a Michael Hanselmann
      files_to_copy.append(constants.CLUSTER_DOMAIN_SECRET_FILE)
650 3db3eb2a Michael Hanselmann
651 6d4a1656 Michael Hanselmann
    if files_to_copy:
652 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
653 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
654 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
655 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
656 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
657 6d4a1656 Michael Hanselmann
658 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
659 6d4a1656 Michael Hanselmann
660 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
661 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
662 6d4a1656 Michael Hanselmann
663 6d4a1656 Michael Hanselmann
  return 0
664 6d4a1656 Michael Hanselmann
665 6d4a1656 Michael Hanselmann
666 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
667 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
668 6d4a1656 Michael Hanselmann
669 6d4a1656 Michael Hanselmann
  """
670 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
671 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
672 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
673 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
674 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
675 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
676 6d4a1656 Michael Hanselmann
                      opts.force)
677 6d4a1656 Michael Hanselmann
678 6d4a1656 Michael Hanselmann
679 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
680 90b6aa3a Manuel Franceschini
  """Modify the cluster.
681 90b6aa3a Manuel Franceschini
682 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
683 469ee405 Iustin Pop
  @type args: list
684 469ee405 Iustin Pop
  @param args: should be an empty list
685 469ee405 Iustin Pop
  @rtype: int
686 469ee405 Iustin Pop
  @return: the desired exit code
687 90b6aa3a Manuel Franceschini
688 90b6aa3a Manuel Franceschini
  """
689 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
690 ed14ed48 Luca Bigliardi
          not opts.drbd_storage or opts.drbd_helper or
691 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
692 5af3da74 Guido Trotter
          opts.beparams or opts.nicparams or
693 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
694 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
695 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
696 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
697 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
698 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
699 f38ea602 Iustin Pop
          opts.reserved_lvs is not None):
700 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
701 90b6aa3a Manuel Franceschini
    return 1
702 90b6aa3a Manuel Franceschini
703 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
704 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
705 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
706 90b6aa3a Manuel Franceschini
    return 1
707 6d4a1656 Michael Hanselmann
708 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
709 6d4a1656 Michael Hanselmann
    vg_name = ""
710 90b6aa3a Manuel Franceschini
711 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
712 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
713 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
714 ed14ed48 Luca Bigliardi
    return 1
715 ed14ed48 Luca Bigliardi
716 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage:
717 ed14ed48 Luca Bigliardi
    drbd_helper = ""
718 ed14ed48 Luca Bigliardi
719 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
720 779c15bb Iustin Pop
  if hvlist is not None:
721 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
722 779c15bb Iustin Pop
723 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
724 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
725 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
726 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
727 779c15bb Iustin Pop
728 779c15bb Iustin Pop
  beparams = opts.beparams
729 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
730 779c15bb Iustin Pop
731 5af3da74 Guido Trotter
  nicparams = opts.nicparams
732 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
733 5af3da74 Guido Trotter
734 1338f2b4 Balazs Lecz
735 3953242f Iustin Pop
  mnh = opts.maintain_node_health
736 3953242f Iustin Pop
737 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
738 1338f2b4 Balazs Lecz
  if uid_pool is not None:
739 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
740 1338f2b4 Balazs Lecz
741 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
742 fdad8c4d Balazs Lecz
  if add_uids is not None:
743 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
744 fdad8c4d Balazs Lecz
745 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
746 fdad8c4d Balazs Lecz
  if remove_uids is not None:
747 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
748 fdad8c4d Balazs Lecz
749 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
750 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
751 f38ea602 Iustin Pop
      opts.reserved_lvs = []
752 f38ea602 Iustin Pop
    else:
753 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
754 f38ea602 Iustin Pop
755 b8a8fbe1 Guido Trotter
  op = opcodes.OpSetClusterParams(vg_name=vg_name,
756 ed14ed48 Luca Bigliardi
                                  drbd_helper=drbd_helper,
757 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
758 779c15bb Iustin Pop
                                  hvparams=hvparams,
759 17463d22 René Nussbaumer
                                  os_hvp=None,
760 4b7735f9 Iustin Pop
                                  beparams=beparams,
761 5af3da74 Guido Trotter
                                  nicparams=nicparams,
762 3953242f Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size,
763 1338f2b4 Balazs Lecz
                                  maintain_node_health=mnh,
764 fdad8c4d Balazs Lecz
                                  uid_pool=uid_pool,
765 fdad8c4d Balazs Lecz
                                  add_uids=add_uids,
766 bf4af505 Apollon Oikonomopoulos
                                  remove_uids=remove_uids,
767 f38ea602 Iustin Pop
                                  default_iallocator=opts.default_iallocator,
768 f38ea602 Iustin Pop
                                  reserved_lvs=opts.reserved_lvs)
769 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
770 90b6aa3a Manuel Franceschini
  return 0
771 90b6aa3a Manuel Franceschini
772 90b6aa3a Manuel Franceschini
773 3ccafd0e Iustin Pop
def QueueOps(opts, args):
774 3ccafd0e Iustin Pop
  """Queue operations.
775 3ccafd0e Iustin Pop
776 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
777 469ee405 Iustin Pop
  @type args: list
778 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
779 469ee405 Iustin Pop
  @rtype: int
780 469ee405 Iustin Pop
  @return: the desired exit code
781 469ee405 Iustin Pop
782 3ccafd0e Iustin Pop
  """
783 3ccafd0e Iustin Pop
  command = args[0]
784 3ccafd0e Iustin Pop
  client = GetClient()
785 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
786 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
787 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
788 3ccafd0e Iustin Pop
  elif command == "info":
789 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
790 3ccafd0e Iustin Pop
    if result[0]:
791 3a24c527 Iustin Pop
      val = "set"
792 3ccafd0e Iustin Pop
    else:
793 3a24c527 Iustin Pop
      val = "unset"
794 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
795 2e668b38 Guido Trotter
  else:
796 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
797 debac808 Iustin Pop
                               errors.ECODE_INVAL)
798 2e668b38 Guido Trotter
799 3ccafd0e Iustin Pop
  return 0
800 3ccafd0e Iustin Pop
801 95b2e626 Michael Hanselmann
802 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
803 28b498cd Michael Hanselmann
  if until is None or until < time.time():
804 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
805 28b498cd Michael Hanselmann
  else:
806 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
807 28b498cd Michael Hanselmann
808 28b498cd Michael Hanselmann
809 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
810 95b2e626 Michael Hanselmann
  """Watcher operations.
811 95b2e626 Michael Hanselmann
812 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
813 95b2e626 Michael Hanselmann
  @type args: list
814 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
815 95b2e626 Michael Hanselmann
  @rtype: int
816 95b2e626 Michael Hanselmann
  @return: the desired exit code
817 95b2e626 Michael Hanselmann
818 95b2e626 Michael Hanselmann
  """
819 95b2e626 Michael Hanselmann
  command = args[0]
820 95b2e626 Michael Hanselmann
  client = GetClient()
821 95b2e626 Michael Hanselmann
822 95b2e626 Michael Hanselmann
  if command == "continue":
823 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
824 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
825 95b2e626 Michael Hanselmann
826 95b2e626 Michael Hanselmann
  elif command == "pause":
827 95b2e626 Michael Hanselmann
    if len(args) < 2:
828 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
829 95b2e626 Michael Hanselmann
830 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
831 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
832 95b2e626 Michael Hanselmann
833 95b2e626 Michael Hanselmann
  elif command == "info":
834 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
835 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
836 95b2e626 Michael Hanselmann
837 95b2e626 Michael Hanselmann
  else:
838 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
839 debac808 Iustin Pop
                               errors.ECODE_INVAL)
840 95b2e626 Michael Hanselmann
841 95b2e626 Michael Hanselmann
  return 0
842 95b2e626 Michael Hanselmann
843 95b2e626 Michael Hanselmann
844 a8083063 Iustin Pop
commands = {
845 6ea815cf Iustin Pop
  'init': (
846 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
847 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
848 6ea815cf Iustin Pop
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
849 b989b9d9 Ken Wehr
     NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
850 39b0f0c2 Balazs Lecz
     SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
851 bf4af505 Apollon Oikonomopoulos
     UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
852 bf4af505 Apollon Oikonomopoulos
     DEFAULT_IALLOCATOR_OPT],
853 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
854 6ea815cf Iustin Pop
  'destroy': (
855 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
856 6ea815cf Iustin Pop
    "", "Destroy cluster"),
857 6ea815cf Iustin Pop
  'rename': (
858 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
859 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
860 6ea815cf Iustin Pop
    "<new_name>",
861 6ea815cf Iustin Pop
    "Renames the cluster"),
862 6ea815cf Iustin Pop
  'redist-conf': (
863 db5a8a2d Iustin Pop
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT, DRY_RUN_OPT],
864 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
865 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
866 6ea815cf Iustin Pop
  'verify': (
867 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
868 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
869 db5a8a2d Iustin Pop
     DRY_RUN_OPT],
870 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
871 6ea815cf Iustin Pop
  'verify-disks': (
872 064c21f8 Iustin Pop
    VerifyDisks, ARGS_NONE, [],
873 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
874 6ea815cf Iustin Pop
  'repair-disk-sizes': (
875 db5a8a2d Iustin Pop
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT],
876 6ea815cf Iustin Pop
    "", "Updates mismatches in recorded disk sizes"),
877 c28502b1 Iustin Pop
  'master-failover': (
878 064c21f8 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT],
879 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
880 4404ffad Iustin Pop
  'master-ping': (
881 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
882 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
883 6ea815cf Iustin Pop
  'version': (
884 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
885 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
886 6ea815cf Iustin Pop
  'getmaster': (
887 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
888 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
889 6ea815cf Iustin Pop
  'copyfile': (
890 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
891 74adc100 Iustin Pop
    [NODE_LIST_OPT, USE_REPL_NET_OPT],
892 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
893 6ea815cf Iustin Pop
  'command': (
894 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
895 064c21f8 Iustin Pop
    [NODE_LIST_OPT],
896 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
897 6ea815cf Iustin Pop
  'info': (
898 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
899 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
900 6ea815cf Iustin Pop
  'list-tags': (
901 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
902 6ea815cf Iustin Pop
  'add-tags': (
903 064c21f8 Iustin Pop
    AddTags, [ArgUnknown()], [TAG_SRC_OPT],
904 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
905 6ea815cf Iustin Pop
  'remove-tags': (
906 064c21f8 Iustin Pop
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT],
907 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
908 6ea815cf Iustin Pop
  'search-tags': (
909 6ea815cf Iustin Pop
    SearchTags, [ArgUnknown(min=1, max=1)],
910 064c21f8 Iustin Pop
    [], "", "Searches the tags on all objects on"
911 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
912 6ea815cf Iustin Pop
  'queue': (
913 6ea815cf Iustin Pop
    QueueOps,
914 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
915 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
916 6ea815cf Iustin Pop
  'watcher': (
917 6ea815cf Iustin Pop
    WatcherOps,
918 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
919 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
920 064c21f8 Iustin Pop
    [],
921 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
922 6ea815cf Iustin Pop
  'modify': (
923 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
924 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT,
925 1338f2b4 Balazs Lecz
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
926 ed14ed48 Luca Bigliardi
     UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT,
927 db5a8a2d Iustin Pop
     NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, RESERVED_LVS_OPT,
928 db5a8a2d Iustin Pop
     DRY_RUN_OPT],
929 6ea815cf Iustin Pop
    "[opts...]",
930 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
931 6d4a1656 Michael Hanselmann
  "renew-crypto": (
932 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
933 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
934 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
935 3db3eb2a Michael Hanselmann
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT],
936 6d4a1656 Michael Hanselmann
    "[opts...]",
937 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
938 a8083063 Iustin Pop
  }
939 a8083063 Iustin Pop
940 6d4a1656 Michael Hanselmann
941 c28502b1 Iustin Pop
#: dictionary with aliases for commands
942 c28502b1 Iustin Pop
aliases = {
943 c28502b1 Iustin Pop
  'masterfailover': 'master-failover',
944 c28502b1 Iustin Pop
}
945 c28502b1 Iustin Pop
946 c28502b1 Iustin Pop
947 a8083063 Iustin Pop
if __name__ == '__main__':
948 c28502b1 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
949 c28502b1 Iustin Pop
                       aliases=aliases))