Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 715462e7

History | View | Annotate | Download (30.8 kB)

1 7b3e7d41 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 2f20d07b Manuel Franceschini
# 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 b3989551 Iustin Pop
import os.path
30 95b2e626 Michael Hanselmann
import time
31 6d4a1656 Michael Hanselmann
import OpenSSL
32 a8083063 Iustin Pop
33 a8083063 Iustin Pop
from ganeti.cli import *
34 a8083063 Iustin Pop
from ganeti import opcodes
35 c2a62a33 Michael Hanselmann
from ganeti import constants
36 f4d4e184 Iustin Pop
from ganeti import errors
37 b63ed789 Iustin Pop
from ganeti import utils
38 a0c9f010 Michael Hanselmann
from ganeti import bootstrap
39 b3989551 Iustin Pop
from ganeti import ssh
40 d3cfe525 Guido Trotter
from ganeti import objects
41 1338f2b4 Balazs Lecz
from ganeti import uidpool
42 cea881e5 Michael Hanselmann
from ganeti import compat
43 a8083063 Iustin Pop
44 a8083063 Iustin Pop
45 4331f6cd Michael Hanselmann
@UsesRPC
46 a8083063 Iustin Pop
def InitCluster(opts, args):
47 a8083063 Iustin Pop
  """Initialize the cluster.
48 a8083063 Iustin Pop

49 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
50 469ee405 Iustin Pop
  @type args: list
51 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
52 469ee405 Iustin Pop
      cluster name
53 469ee405 Iustin Pop
  @rtype: int
54 469ee405 Iustin Pop
  @return: the desired exit code
55 a8083063 Iustin Pop

56 a8083063 Iustin Pop
  """
57 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
58 3a24c527 Iustin Pop
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
59 90b6aa3a Manuel Franceschini
    return 1
60 90b6aa3a Manuel Franceschini
61 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
62 90b6aa3a Manuel Franceschini
  if opts.lvm_storage and not opts.vg_name:
63 90b6aa3a Manuel Franceschini
    vg_name = constants.DEFAULT_VG
64 90b6aa3a Manuel Franceschini
65 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
66 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
67 ed14ed48 Luca Bigliardi
    return 1
68 ed14ed48 Luca Bigliardi
69 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
70 ed14ed48 Luca Bigliardi
  if opts.drbd_storage and not opts.drbd_helper:
71 ed14ed48 Luca Bigliardi
    drbd_helper = constants.DEFAULT_DRBD_HELPER
72 ed14ed48 Luca Bigliardi
73 25be0c75 Guido Trotter
  master_netdev = opts.master_netdev
74 25be0c75 Guido Trotter
  if master_netdev is None:
75 25be0c75 Guido Trotter
    master_netdev = constants.DEFAULT_BRIDGE
76 25be0c75 Guido Trotter
77 ea3a925f Alexander Schreiber
  hvlist = opts.enabled_hypervisors
78 383a3591 Iustin Pop
  if hvlist is None:
79 383a3591 Iustin Pop
    hvlist = constants.DEFAULT_ENABLED_HYPERVISOR
80 066f465d Guido Trotter
  hvlist = hvlist.split(",")
81 ea3a925f Alexander Schreiber
82 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
83 ea3a925f Alexander Schreiber
  beparams = opts.beparams
84 b6a30b0d Guido Trotter
  nicparams = opts.nicparams
85 ea3a925f Alexander Schreiber
86 ea3a925f Alexander Schreiber
  # prepare beparams dict
87 d3cfe525 Guido Trotter
  beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams)
88 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
89 ea3a925f Alexander Schreiber
90 b6a30b0d Guido Trotter
  # prepare nicparams dict
91 b6a30b0d Guido Trotter
  nicparams = objects.FillDict(constants.NICC_DEFAULTS, nicparams)
92 b6a30b0d Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
93 b6a30b0d Guido Trotter
94 6204ee71 René Nussbaumer
  # prepare ndparams dict
95 6204ee71 René Nussbaumer
  if opts.ndparams is None:
96 6204ee71 René Nussbaumer
    ndparams = dict(constants.NDC_DEFAULTS)
97 6204ee71 René Nussbaumer
  else:
98 6204ee71 René Nussbaumer
    ndparams = objects.FillDict(constants.NDC_DEFAULTS, opts.ndparams)
99 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
100 6204ee71 René Nussbaumer
101 ea3a925f Alexander Schreiber
  # prepare hvparams dict
102 ea3a925f Alexander Schreiber
  for hv in constants.HYPER_TYPES:
103 ea3a925f Alexander Schreiber
    if hv not in hvparams:
104 ea3a925f Alexander Schreiber
      hvparams[hv] = {}
105 d3cfe525 Guido Trotter
    hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv])
106 a5728081 Guido Trotter
    utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES)
107 ea3a925f Alexander Schreiber
108 e32df528 Iustin Pop
  if opts.candidate_pool_size is None:
109 e32df528 Iustin Pop
    opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT
110 e32df528 Iustin Pop
111 e3646f22 Iustin Pop
  if opts.mac_prefix is None:
112 e3646f22 Iustin Pop
    opts.mac_prefix = constants.DEFAULT_MAC_PREFIX
113 e3646f22 Iustin Pop
114 39b0f0c2 Balazs Lecz
  uid_pool = opts.uid_pool
115 39b0f0c2 Balazs Lecz
  if uid_pool is not None:
116 39b0f0c2 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
117 39b0f0c2 Balazs Lecz
118 b883637f René Nussbaumer
  if opts.prealloc_wipe_disks is None:
119 b883637f René Nussbaumer
    opts.prealloc_wipe_disks = False
120 b883637f René Nussbaumer
121 e7323b5e Manuel Franceschini
  try:
122 e7323b5e Manuel Franceschini
    primary_ip_version = int(opts.primary_ip_version)
123 e7323b5e Manuel Franceschini
  except (ValueError, TypeError), err:
124 e7323b5e Manuel Franceschini
    ToStderr("Invalid primary ip version value: %s" % str(err))
125 e7323b5e Manuel Franceschini
    return 1
126 e7323b5e Manuel Franceschini
127 a0c9f010 Michael Hanselmann
  bootstrap.InitCluster(cluster_name=args[0],
128 a0c9f010 Michael Hanselmann
                        secondary_ip=opts.secondary_ip,
129 a0c9f010 Michael Hanselmann
                        vg_name=vg_name,
130 a0c9f010 Michael Hanselmann
                        mac_prefix=opts.mac_prefix,
131 25be0c75 Guido Trotter
                        master_netdev=master_netdev,
132 ea3a925f Alexander Schreiber
                        file_storage_dir=opts.file_storage_dir,
133 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
134 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
135 ce735215 Guido Trotter
                        beparams=beparams,
136 b6a30b0d Guido Trotter
                        nicparams=nicparams,
137 6204ee71 René Nussbaumer
                        ndparams=ndparams,
138 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
139 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
140 b989b9d9 Ken Wehr
                        modify_ssh_setup=opts.modify_ssh_setup,
141 3953242f Iustin Pop
                        maintain_node_health=opts.maintain_node_health,
142 ed14ed48 Luca Bigliardi
                        drbd_helper=drbd_helper,
143 39b0f0c2 Balazs Lecz
                        uid_pool=uid_pool,
144 bf4af505 Apollon Oikonomopoulos
                        default_iallocator=opts.default_iallocator,
145 e7323b5e Manuel Franceschini
                        primary_ip_version=primary_ip_version,
146 b18ecea2 René Nussbaumer
                        prealloc_wipe_disks=opts.prealloc_wipe_disks,
147 ce735215 Guido Trotter
                        )
148 bc84ffa7 Iustin Pop
  op = opcodes.OpClusterPostInit()
149 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
150 a8083063 Iustin Pop
  return 0
151 a8083063 Iustin Pop
152 a8083063 Iustin Pop
153 4331f6cd Michael Hanselmann
@UsesRPC
154 a8083063 Iustin Pop
def DestroyCluster(opts, args):
155 a8083063 Iustin Pop
  """Destroy the cluster.
156 a8083063 Iustin Pop

157 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
158 469ee405 Iustin Pop
  @type args: list
159 469ee405 Iustin Pop
  @param args: should be an empty list
160 469ee405 Iustin Pop
  @rtype: int
161 469ee405 Iustin Pop
  @return: the desired exit code
162 098c0958 Michael Hanselmann

163 a8083063 Iustin Pop
  """
164 a8083063 Iustin Pop
  if not opts.yes_do_it:
165 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
166 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
167 a8083063 Iustin Pop
    return 1
168 a8083063 Iustin Pop
169 c6d43e9e Iustin Pop
  op = opcodes.OpClusterDestroy()
170 400ca2f7 Iustin Pop
  master = SubmitOpCode(op, opts=opts)
171 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
172 140aa4a8 Iustin Pop
  # shutdown all the daemons
173 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
174 a8083063 Iustin Pop
  return 0
175 a8083063 Iustin Pop
176 a8083063 Iustin Pop
177 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
178 07bd8a51 Iustin Pop
  """Rename the cluster.
179 07bd8a51 Iustin Pop

180 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
181 469ee405 Iustin Pop
  @type args: list
182 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
183 469ee405 Iustin Pop
  @rtype: int
184 469ee405 Iustin Pop
  @return: the desired exit code
185 07bd8a51 Iustin Pop

186 07bd8a51 Iustin Pop
  """
187 6a016df9 Michael Hanselmann
  cl = GetClient()
188 6a016df9 Michael Hanselmann
189 6a016df9 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
190 6a016df9 Michael Hanselmann
191 6a016df9 Michael Hanselmann
  new_name = args[0]
192 07bd8a51 Iustin Pop
  if not opts.force:
193 6a016df9 Michael Hanselmann
    usertext = ("This will rename the cluster from '%s' to '%s'. If you are"
194 6a016df9 Michael Hanselmann
                " connected over the network to the cluster name, the"
195 6a016df9 Michael Hanselmann
                " operation is very dangerous as the IP address will be"
196 6a016df9 Michael Hanselmann
                " removed from the node and the change may not go through."
197 6a016df9 Michael Hanselmann
                " Continue?") % (cluster_name, new_name)
198 47988778 Iustin Pop
    if not AskUser(usertext):
199 07bd8a51 Iustin Pop
      return 1
200 07bd8a51 Iustin Pop
201 e126df25 Iustin Pop
  op = opcodes.OpClusterRename(name=new_name)
202 6a016df9 Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
203 6a016df9 Michael Hanselmann
204 48418fea Iustin Pop
  if result:
205 48418fea Iustin Pop
    ToStdout("Cluster renamed from '%s' to '%s'", cluster_name, result)
206 6a016df9 Michael Hanselmann
207 07bd8a51 Iustin Pop
  return 0
208 07bd8a51 Iustin Pop
209 07bd8a51 Iustin Pop
210 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
211 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
212 afee0879 Iustin Pop

213 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
214 afee0879 Iustin Pop
  @type args: list
215 afee0879 Iustin Pop
  @param args: empty list
216 afee0879 Iustin Pop
  @rtype: int
217 afee0879 Iustin Pop
  @return: the desired exit code
218 afee0879 Iustin Pop

219 afee0879 Iustin Pop
  """
220 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
221 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
222 afee0879 Iustin Pop
  return 0
223 afee0879 Iustin Pop
224 afee0879 Iustin Pop
225 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
226 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
227 a8083063 Iustin Pop

228 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
229 469ee405 Iustin Pop
  @type args: list
230 469ee405 Iustin Pop
  @param args: should be an empty list
231 469ee405 Iustin Pop
  @rtype: int
232 469ee405 Iustin Pop
  @return: the desired exit code
233 a8083063 Iustin Pop

234 a8083063 Iustin Pop
  """
235 2e7b8369 Iustin Pop
  cl = GetClient()
236 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
237 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
238 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
239 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
240 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
241 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
242 a8083063 Iustin Pop
  return 0
243 a8083063 Iustin Pop
244 a8083063 Iustin Pop
245 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
246 a8083063 Iustin Pop
  """Write name of master node to the standard output.
247 a8083063 Iustin Pop

248 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
249 469ee405 Iustin Pop
  @type args: list
250 469ee405 Iustin Pop
  @param args: should be an empty list
251 469ee405 Iustin Pop
  @rtype: int
252 469ee405 Iustin Pop
  @return: the desired exit code
253 a8083063 Iustin Pop

254 a8083063 Iustin Pop
  """
255 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
256 8eb148ae Iustin Pop
  ToStdout(master)
257 a8083063 Iustin Pop
  return 0
258 a8083063 Iustin Pop
259 cac599f1 Michael Hanselmann
260 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
261 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
262 1094acda Guido Trotter

263 1094acda Guido Trotter
  @type paramsdict: dict of dicts
264 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
265 664a9d73 René Nussbaumer
  @type level: int
266 664a9d73 René Nussbaumer
  @param level: Level of indention
267 1094acda Guido Trotter

268 1094acda Guido Trotter
  """
269 664a9d73 René Nussbaumer
  indent = "  " * level
270 9d91c6ab Guido Trotter
  for item, val in sorted(paramsdict.items()):
271 664a9d73 René Nussbaumer
    if isinstance(val, dict):
272 664a9d73 René Nussbaumer
      ToStdout("%s- %s:", indent, item)
273 d729e03a Guido Trotter
      _PrintGroupedParams(val, level=level + 1, roman=roman)
274 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
275 d729e03a Guido Trotter
      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
276 664a9d73 René Nussbaumer
    else:
277 664a9d73 René Nussbaumer
      ToStdout("%s  %s: %s", indent, item, val)
278 a8083063 Iustin Pop
279 cac599f1 Michael Hanselmann
280 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
281 a8083063 Iustin Pop
  """Shows cluster information.
282 a8083063 Iustin Pop

283 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
284 469ee405 Iustin Pop
  @type args: list
285 469ee405 Iustin Pop
  @param args: should be an empty list
286 469ee405 Iustin Pop
  @rtype: int
287 469ee405 Iustin Pop
  @return: the desired exit code
288 469ee405 Iustin Pop

289 a8083063 Iustin Pop
  """
290 2e7b8369 Iustin Pop
  cl = GetClient()
291 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
292 a8083063 Iustin Pop
293 3a24c527 Iustin Pop
  ToStdout("Cluster name: %s", result["name"])
294 259578eb Iustin Pop
  ToStdout("Cluster UUID: %s", result["uuid"])
295 a8083063 Iustin Pop
296 90f72445 Iustin Pop
  ToStdout("Creation time: %s", utils.FormatTime(result["ctime"]))
297 90f72445 Iustin Pop
  ToStdout("Modification time: %s", utils.FormatTime(result["mtime"]))
298 90f72445 Iustin Pop
299 3a24c527 Iustin Pop
  ToStdout("Master node: %s", result["master"])
300 a8083063 Iustin Pop
301 3a24c527 Iustin Pop
  ToStdout("Architecture (this node): %s (%s)",
302 3a24c527 Iustin Pop
           result["architecture"][0], result["architecture"][1])
303 a8083063 Iustin Pop
304 c118d1f4 Michael Hanselmann
  if result["tags"]:
305 1f864b60 Iustin Pop
    tags = utils.CommaJoin(utils.NiceSort(result["tags"]))
306 c118d1f4 Michael Hanselmann
  else:
307 c118d1f4 Michael Hanselmann
    tags = "(none)"
308 c118d1f4 Michael Hanselmann
309 c118d1f4 Michael Hanselmann
  ToStdout("Tags: %s", tags)
310 c118d1f4 Michael Hanselmann
311 02691904 Alexander Schreiber
  ToStdout("Default hypervisor: %s", result["default_hypervisor"])
312 1f864b60 Iustin Pop
  ToStdout("Enabled hypervisors: %s",
313 1f864b60 Iustin Pop
           utils.CommaJoin(result["enabled_hypervisors"]))
314 469f88e1 Iustin Pop
315 3a24c527 Iustin Pop
  ToStdout("Hypervisor parameters:")
316 1094acda Guido Trotter
  _PrintGroupedParams(result["hvparams"])
317 469f88e1 Iustin Pop
318 dbb24ec7 Iustin Pop
  ToStdout("OS-specific hypervisor parameters:")
319 664a9d73 René Nussbaumer
  _PrintGroupedParams(result["os_hvp"])
320 664a9d73 René Nussbaumer
321 dbb24ec7 Iustin Pop
  ToStdout("OS parameters:")
322 dbb24ec7 Iustin Pop
  _PrintGroupedParams(result["osparams"])
323 dbb24ec7 Iustin Pop
324 3a24c527 Iustin Pop
  ToStdout("Cluster parameters:")
325 d729e03a Guido Trotter
  ToStdout("  - candidate pool size: %s",
326 d729e03a Guido Trotter
            compat.TryToRoman(result["candidate_pool_size"],
327 d729e03a Guido Trotter
                              convert=opts.roman_integers))
328 a8001106 Guido Trotter
  ToStdout("  - master netdev: %s", result["master_netdev"])
329 a8001106 Guido Trotter
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
330 5a3ab484 Iustin Pop
  if result["reserved_lvs"]:
331 5a3ab484 Iustin Pop
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
332 5a3ab484 Iustin Pop
  else:
333 5a3ab484 Iustin Pop
    reserved_lvs = "(none)"
334 5a3ab484 Iustin Pop
  ToStdout("  - lvm reserved volumes: %s", reserved_lvs)
335 ed14ed48 Luca Bigliardi
  ToStdout("  - drbd usermode helper: %s", result["drbd_usermode_helper"])
336 a8001106 Guido Trotter
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
337 3953242f Iustin Pop
  ToStdout("  - maintenance of node health: %s",
338 3953242f Iustin Pop
           result["maintain_node_health"])
339 d729e03a Guido Trotter
  ToStdout("  - uid pool: %s",
340 d729e03a Guido Trotter
            uidpool.FormatUidPool(result["uid_pool"],
341 d729e03a Guido Trotter
                                  roman=opts.roman_integers))
342 bf4af505 Apollon Oikonomopoulos
  ToStdout("  - default instance allocator: %s", result["default_iallocator"])
343 e7323b5e Manuel Franceschini
  ToStdout("  - primary ip version: %d", result["primary_ip_version"])
344 b18ecea2 René Nussbaumer
  ToStdout("  - preallocation wipe disks: %s", result["prealloc_wipe_disks"])
345 4b7735f9 Iustin Pop
346 88be69ee René Nussbaumer
  ToStdout("Default node parameters:")
347 88be69ee René Nussbaumer
  _PrintGroupedParams(result["ndparams"], roman=opts.roman_integers)
348 88be69ee René Nussbaumer
349 4b7735f9 Iustin Pop
  ToStdout("Default instance parameters:")
350 d729e03a Guido Trotter
  _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
351 1094acda Guido Trotter
352 1094acda Guido Trotter
  ToStdout("Default nic parameters:")
353 d729e03a Guido Trotter
  _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers)
354 8a12ce45 Iustin Pop
355 a8083063 Iustin Pop
  return 0
356 a8083063 Iustin Pop
357 a8083063 Iustin Pop
358 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
359 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
360 a8083063 Iustin Pop

361 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
362 469ee405 Iustin Pop
  @type args: list
363 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
364 469ee405 Iustin Pop
      the file to be copied
365 469ee405 Iustin Pop
  @rtype: int
366 469ee405 Iustin Pop
  @return: the desired exit code
367 a8083063 Iustin Pop

368 a8083063 Iustin Pop
  """
369 b3989551 Iustin Pop
  filename = args[0]
370 b3989551 Iustin Pop
  if not os.path.exists(filename):
371 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
372 debac808 Iustin Pop
                               errors.ECODE_INVAL)
373 b3989551 Iustin Pop
374 56bece1f Iustin Pop
  cl = GetClient()
375 56bece1f Iustin Pop
376 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
377 56bece1f Iustin Pop
378 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
379 74adc100 Iustin Pop
                           secondary_ips=opts.use_replication_network)
380 e00ea635 Michael Hanselmann
381 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
382 b3989551 Iustin Pop
  for node in results:
383 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
384 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
385 b3989551 Iustin Pop
386 a8083063 Iustin Pop
  return 0
387 a8083063 Iustin Pop
388 a8083063 Iustin Pop
389 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
390 a8083063 Iustin Pop
  """Run a command on some nodes.
391 a8083063 Iustin Pop

392 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
393 469ee405 Iustin Pop
  @type args: list
394 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
395 469ee405 Iustin Pop
  @rtype: int
396 469ee405 Iustin Pop
  @return: the desired exit code
397 a8083063 Iustin Pop

398 a8083063 Iustin Pop
  """
399 56bece1f Iustin Pop
  cl = GetClient()
400 7688d0d3 Michael Hanselmann
401 a8083063 Iustin Pop
  command = " ".join(args)
402 4040a784 Iustin Pop
403 4040a784 Iustin Pop
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl)
404 56bece1f Iustin Pop
405 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
406 56bece1f Iustin Pop
                                                    "master_node"])
407 b3989551 Iustin Pop
408 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
409 b3989551 Iustin Pop
410 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
411 b3989551 Iustin Pop
  if master_node in nodes:
412 b3989551 Iustin Pop
    nodes.remove(master_node)
413 b3989551 Iustin Pop
    nodes.append(master_node)
414 b3989551 Iustin Pop
415 b3989551 Iustin Pop
  for name in nodes:
416 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
417 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
418 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
419 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
420 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
421 b3989551 Iustin Pop
422 b3989551 Iustin Pop
  return 0
423 a8083063 Iustin Pop
424 a8083063 Iustin Pop
425 a8083063 Iustin Pop
def VerifyCluster(opts, args):
426 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
427 a8083063 Iustin Pop

428 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
429 469ee405 Iustin Pop
  @type args: list
430 469ee405 Iustin Pop
  @param args: should be an empty list
431 469ee405 Iustin Pop
  @rtype: int
432 469ee405 Iustin Pop
  @return: the desired exit code
433 a8083063 Iustin Pop

434 a8083063 Iustin Pop
  """
435 8d59409f Iustin Pop
  skip_checks = []
436 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
437 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
438 a3d32770 Iustin Pop
  op = opcodes.OpClusterVerify(skip_checks=skip_checks,
439 7c874ee1 Iustin Pop
                               verbose=opts.verbose,
440 a0c9776a Iustin Pop
                               error_codes=opts.error_codes,
441 a0c9776a Iustin Pop
                               debug_simulate_errors=opts.simulate_errors)
442 400ca2f7 Iustin Pop
  if SubmitOpCode(op, opts=opts):
443 34290825 Michael Hanselmann
    return 0
444 34290825 Michael Hanselmann
  else:
445 34290825 Michael Hanselmann
    return 1
446 a8083063 Iustin Pop
447 a8083063 Iustin Pop
448 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
449 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
450 f4d4e184 Iustin Pop

451 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
452 469ee405 Iustin Pop
  @type args: list
453 469ee405 Iustin Pop
  @param args: should be an empty list
454 469ee405 Iustin Pop
  @rtype: int
455 469ee405 Iustin Pop
  @return: the desired exit code
456 f4d4e184 Iustin Pop

457 f4d4e184 Iustin Pop
  """
458 f1b083ce Michael Hanselmann
  cl = GetClient()
459 f1b083ce Michael Hanselmann
460 bd8210a7 Iustin Pop
  op = opcodes.OpClusterVerifyDisks()
461 f1b083ce Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
462 29d376ec Iustin Pop
  if not isinstance(result, (list, tuple)) or len(result) != 3:
463 bd8210a7 Iustin Pop
    raise errors.ProgrammerError("Unknown result type for OpClusterVerifyDisks")
464 f4d4e184 Iustin Pop
465 29d376ec Iustin Pop
  bad_nodes, instances, missing = result
466 b63ed789 Iustin Pop
467 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
468 b63ed789 Iustin Pop
469 29d376ec Iustin Pop
  if bad_nodes:
470 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
471 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
472 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
473 b63ed789 Iustin Pop
      retcode |= 1
474 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
475 b63ed789 Iustin Pop
476 f4d4e184 Iustin Pop
  if instances:
477 f4d4e184 Iustin Pop
    for iname in instances:
478 b63ed789 Iustin Pop
      if iname in missing:
479 b63ed789 Iustin Pop
        continue
480 83f5d475 Iustin Pop
      op = opcodes.OpInstanceActivateDisks(instance_name=iname)
481 f4d4e184 Iustin Pop
      try:
482 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
483 f1b083ce Michael Hanselmann
        SubmitOpCode(op, opts=opts, cl=cl)
484 f4d4e184 Iustin Pop
      except errors.GenericError, err:
485 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
486 f4d4e184 Iustin Pop
        retcode |= nret
487 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
488 b63ed789 Iustin Pop
489 b63ed789 Iustin Pop
  if missing:
490 f1b083ce Michael Hanselmann
    (vg_name, ) = cl.QueryConfigValues(["volume_group_name"])
491 f1b083ce Michael Hanselmann
492 b63ed789 Iustin Pop
    for iname, ival in missing.iteritems():
493 403f5172 Guido Trotter
      all_missing = compat.all(x[0] in bad_nodes for x in ival)
494 b63ed789 Iustin Pop
      if all_missing:
495 3a24c527 Iustin Pop
        ToStdout("Instance %s cannot be verified as it lives on"
496 3a24c527 Iustin Pop
                 " broken nodes", iname)
497 b63ed789 Iustin Pop
      else:
498 3a24c527 Iustin Pop
        ToStdout("Instance %s has missing logical volumes:", iname)
499 b63ed789 Iustin Pop
        ival.sort()
500 b63ed789 Iustin Pop
        for node, vol in ival:
501 29d376ec Iustin Pop
          if node in bad_nodes:
502 f1b083ce Michael Hanselmann
            ToStdout("\tbroken node %s /dev/%s/%s", node, vg_name, vol)
503 b63ed789 Iustin Pop
          else:
504 f1b083ce Michael Hanselmann
            ToStdout("\t%s /dev/%s/%s", node, vg_name, vol)
505 f1b083ce Michael Hanselmann
506 3a24c527 Iustin Pop
    ToStdout("You need to run replace_disks for all the above"
507 f1b083ce Michael Hanselmann
             " instances, if this message persist after fixing nodes.")
508 b63ed789 Iustin Pop
    retcode |= 1
509 f4d4e184 Iustin Pop
510 f4d4e184 Iustin Pop
  return retcode
511 f4d4e184 Iustin Pop
512 f4d4e184 Iustin Pop
513 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
514 60975797 Iustin Pop
  """Verify sizes of cluster disks.
515 60975797 Iustin Pop

516 60975797 Iustin Pop
  @param opts: the command line options selected by the user
517 60975797 Iustin Pop
  @type args: list
518 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
519 60975797 Iustin Pop
  @rtype: int
520 60975797 Iustin Pop
  @return: the desired exit code
521 60975797 Iustin Pop

522 60975797 Iustin Pop
  """
523 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
524 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
525 60975797 Iustin Pop
526 60975797 Iustin Pop
527 4331f6cd Michael Hanselmann
@UsesRPC
528 a8083063 Iustin Pop
def MasterFailover(opts, args):
529 a8083063 Iustin Pop
  """Failover the master node.
530 a8083063 Iustin Pop

531 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
532 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
533 a8083063 Iustin Pop
  master.
534 a8083063 Iustin Pop

535 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
536 469ee405 Iustin Pop
  @type args: list
537 469ee405 Iustin Pop
  @param args: should be an empty list
538 469ee405 Iustin Pop
  @rtype: int
539 469ee405 Iustin Pop
  @return: the desired exit code
540 469ee405 Iustin Pop

541 a8083063 Iustin Pop
  """
542 8e2524c3 Guido Trotter
  if opts.no_voting:
543 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
544 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
545 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
546 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
547 8e2524c3 Guido Trotter
    if not AskUser(usertext):
548 8e2524c3 Guido Trotter
      return 1
549 8e2524c3 Guido Trotter
550 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
551 a8083063 Iustin Pop
552 a8083063 Iustin Pop
553 4404ffad Iustin Pop
def MasterPing(opts, args):
554 4404ffad Iustin Pop
  """Checks if the master is alive.
555 4404ffad Iustin Pop

556 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
557 4404ffad Iustin Pop
  @type args: list
558 4404ffad Iustin Pop
  @param args: should be an empty list
559 4404ffad Iustin Pop
  @rtype: int
560 4404ffad Iustin Pop
  @return: the desired exit code
561 4404ffad Iustin Pop

562 4404ffad Iustin Pop
  """
563 4404ffad Iustin Pop
  try:
564 4404ffad Iustin Pop
    cl = GetClient()
565 4404ffad Iustin Pop
    cl.QueryClusterInfo()
566 4404ffad Iustin Pop
    return 0
567 4404ffad Iustin Pop
  except Exception: # pylint: disable-msg=W0703
568 4404ffad Iustin Pop
    return 1
569 4404ffad Iustin Pop
570 4404ffad Iustin Pop
571 73415719 Iustin Pop
def SearchTags(opts, args):
572 73415719 Iustin Pop
  """Searches the tags on all the cluster.
573 73415719 Iustin Pop

574 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
575 469ee405 Iustin Pop
  @type args: list
576 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
577 469ee405 Iustin Pop
  @rtype: int
578 469ee405 Iustin Pop
  @return: the desired exit code
579 469ee405 Iustin Pop

580 73415719 Iustin Pop
  """
581 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
582 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
583 73415719 Iustin Pop
  if not result:
584 73415719 Iustin Pop
    return 1
585 73415719 Iustin Pop
  result = list(result)
586 73415719 Iustin Pop
  result.sort()
587 73415719 Iustin Pop
  for path, tag in result:
588 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
589 73415719 Iustin Pop
590 73415719 Iustin Pop
591 6d4a1656 Michael Hanselmann
def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
592 3db3eb2a Michael Hanselmann
                 new_confd_hmac_key, new_cds, cds_filename,
593 3db3eb2a Michael Hanselmann
                 force):
594 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
595 6d4a1656 Michael Hanselmann

596 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
597 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
598 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
599 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
600 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
601 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
602 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
603 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
604 3db3eb2a Michael Hanselmann
  @type new_cds: bool
605 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
606 3db3eb2a Michael Hanselmann
  @type cds_filename: string
607 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
608 6d4a1656 Michael Hanselmann
  @type force: bool
609 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
610 6d4a1656 Michael Hanselmann

611 6d4a1656 Michael Hanselmann
  """
612 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
613 6d4a1656 Michael Hanselmann
    ToStderr("Only one of the --new-rapi-certficate and --rapi-certificate"
614 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
615 6d4a1656 Michael Hanselmann
    return 1
616 6d4a1656 Michael Hanselmann
617 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
618 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
619 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
620 3db3eb2a Michael Hanselmann
             " the same time.")
621 3db3eb2a Michael Hanselmann
    return 1
622 3db3eb2a Michael Hanselmann
623 6d4a1656 Michael Hanselmann
  if rapi_cert_filename:
624 6d4a1656 Michael Hanselmann
    # Read and verify new certificate
625 6d4a1656 Michael Hanselmann
    try:
626 6d4a1656 Michael Hanselmann
      rapi_cert_pem = utils.ReadFile(rapi_cert_filename)
627 6d4a1656 Michael Hanselmann
628 6d4a1656 Michael Hanselmann
      OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
629 6d4a1656 Michael Hanselmann
                                      rapi_cert_pem)
630 6d4a1656 Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
631 6d4a1656 Michael Hanselmann
      ToStderr("Can't load new RAPI certificate from %s: %s" %
632 6d4a1656 Michael Hanselmann
               (rapi_cert_filename, str(err)))
633 6d4a1656 Michael Hanselmann
      return 1
634 6d4a1656 Michael Hanselmann
635 6d4a1656 Michael Hanselmann
    try:
636 6d4a1656 Michael Hanselmann
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, rapi_cert_pem)
637 6d4a1656 Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
638 6d4a1656 Michael Hanselmann
      ToStderr("Can't load new RAPI private key from %s: %s" %
639 6d4a1656 Michael Hanselmann
               (rapi_cert_filename, str(err)))
640 6d4a1656 Michael Hanselmann
      return 1
641 6d4a1656 Michael Hanselmann
642 6d4a1656 Michael Hanselmann
  else:
643 6d4a1656 Michael Hanselmann
    rapi_cert_pem = None
644 6d4a1656 Michael Hanselmann
645 3db3eb2a Michael Hanselmann
  if cds_filename:
646 3db3eb2a Michael Hanselmann
    try:
647 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
648 3db3eb2a Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
649 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
650 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
651 3db3eb2a Michael Hanselmann
      return 1
652 3db3eb2a Michael Hanselmann
  else:
653 3db3eb2a Michael Hanselmann
    cds = None
654 3db3eb2a Michael Hanselmann
655 6d4a1656 Michael Hanselmann
  if not force:
656 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
657 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
658 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
659 6d4a1656 Michael Hanselmann
      return 1
660 6d4a1656 Michael Hanselmann
661 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
662 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
663 6d4a1656 Michael Hanselmann
    bootstrap.GenerateClusterCrypto(new_cluster_cert, new_rapi_cert,
664 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
665 3db3eb2a Michael Hanselmann
                                    new_cds,
666 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
667 3db3eb2a Michael Hanselmann
                                    cds=cds)
668 6d4a1656 Michael Hanselmann
669 6d4a1656 Michael Hanselmann
    files_to_copy = []
670 6d4a1656 Michael Hanselmann
671 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
672 168c1de2 Michael Hanselmann
      files_to_copy.append(constants.NODED_CERT_FILE)
673 6d4a1656 Michael Hanselmann
674 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
675 6d4a1656 Michael Hanselmann
      files_to_copy.append(constants.RAPI_CERT_FILE)
676 6d4a1656 Michael Hanselmann
677 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
678 6b7d5878 Michael Hanselmann
      files_to_copy.append(constants.CONFD_HMAC_KEY)
679 6d4a1656 Michael Hanselmann
680 3db3eb2a Michael Hanselmann
    if new_cds or cds:
681 3db3eb2a Michael Hanselmann
      files_to_copy.append(constants.CLUSTER_DOMAIN_SECRET_FILE)
682 3db3eb2a Michael Hanselmann
683 6d4a1656 Michael Hanselmann
    if files_to_copy:
684 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
685 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
686 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
687 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
688 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
689 6d4a1656 Michael Hanselmann
690 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
691 6d4a1656 Michael Hanselmann
692 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
693 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
694 6d4a1656 Michael Hanselmann
695 6d4a1656 Michael Hanselmann
  return 0
696 6d4a1656 Michael Hanselmann
697 6d4a1656 Michael Hanselmann
698 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
699 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
700 6d4a1656 Michael Hanselmann

701 6d4a1656 Michael Hanselmann
  """
702 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
703 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
704 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
705 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
706 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
707 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
708 6d4a1656 Michael Hanselmann
                      opts.force)
709 6d4a1656 Michael Hanselmann
710 6d4a1656 Michael Hanselmann
711 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
712 90b6aa3a Manuel Franceschini
  """Modify the cluster.
713 90b6aa3a Manuel Franceschini

714 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
715 469ee405 Iustin Pop
  @type args: list
716 469ee405 Iustin Pop
  @param args: should be an empty list
717 469ee405 Iustin Pop
  @rtype: int
718 469ee405 Iustin Pop
  @return: the desired exit code
719 90b6aa3a Manuel Franceschini

720 90b6aa3a Manuel Franceschini
  """
721 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
722 ed14ed48 Luca Bigliardi
          not opts.drbd_storage or opts.drbd_helper or
723 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
724 6204ee71 René Nussbaumer
          opts.beparams or opts.nicparams or opts.ndparams or
725 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
726 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
727 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
728 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
729 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
730 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
731 b883637f René Nussbaumer
          opts.reserved_lvs is not None or
732 38f9d2cf Guido Trotter
          opts.master_netdev is not None or
733 b883637f René Nussbaumer
          opts.prealloc_wipe_disks is not None):
734 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
735 90b6aa3a Manuel Franceschini
    return 1
736 90b6aa3a Manuel Franceschini
737 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
738 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
739 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
740 90b6aa3a Manuel Franceschini
    return 1
741 6d4a1656 Michael Hanselmann
742 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
743 6d4a1656 Michael Hanselmann
    vg_name = ""
744 90b6aa3a Manuel Franceschini
745 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
746 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
747 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
748 ed14ed48 Luca Bigliardi
    return 1
749 ed14ed48 Luca Bigliardi
750 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage:
751 ed14ed48 Luca Bigliardi
    drbd_helper = ""
752 ed14ed48 Luca Bigliardi
753 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
754 779c15bb Iustin Pop
  if hvlist is not None:
755 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
756 779c15bb Iustin Pop
757 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
758 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
759 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
760 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
761 779c15bb Iustin Pop
762 779c15bb Iustin Pop
  beparams = opts.beparams
763 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
764 779c15bb Iustin Pop
765 5af3da74 Guido Trotter
  nicparams = opts.nicparams
766 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
767 5af3da74 Guido Trotter
768 6204ee71 René Nussbaumer
  ndparams = opts.ndparams
769 6204ee71 René Nussbaumer
  if ndparams is not None:
770 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
771 1338f2b4 Balazs Lecz
772 3953242f Iustin Pop
  mnh = opts.maintain_node_health
773 3953242f Iustin Pop
774 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
775 1338f2b4 Balazs Lecz
  if uid_pool is not None:
776 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
777 1338f2b4 Balazs Lecz
778 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
779 fdad8c4d Balazs Lecz
  if add_uids is not None:
780 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
781 fdad8c4d Balazs Lecz
782 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
783 fdad8c4d Balazs Lecz
  if remove_uids is not None:
784 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
785 fdad8c4d Balazs Lecz
786 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
787 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
788 f38ea602 Iustin Pop
      opts.reserved_lvs = []
789 f38ea602 Iustin Pop
    else:
790 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
791 f38ea602 Iustin Pop
792 a6682fdc Iustin Pop
  op = opcodes.OpClusterSetParams(vg_name=vg_name,
793 ed14ed48 Luca Bigliardi
                                  drbd_helper=drbd_helper,
794 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
795 779c15bb Iustin Pop
                                  hvparams=hvparams,
796 17463d22 René Nussbaumer
                                  os_hvp=None,
797 4b7735f9 Iustin Pop
                                  beparams=beparams,
798 5af3da74 Guido Trotter
                                  nicparams=nicparams,
799 6204ee71 René Nussbaumer
                                  ndparams=ndparams,
800 3953242f Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size,
801 1338f2b4 Balazs Lecz
                                  maintain_node_health=mnh,
802 fdad8c4d Balazs Lecz
                                  uid_pool=uid_pool,
803 fdad8c4d Balazs Lecz
                                  add_uids=add_uids,
804 bf4af505 Apollon Oikonomopoulos
                                  remove_uids=remove_uids,
805 f38ea602 Iustin Pop
                                  default_iallocator=opts.default_iallocator,
806 b883637f René Nussbaumer
                                  prealloc_wipe_disks=opts.prealloc_wipe_disks,
807 38f9d2cf Guido Trotter
                                  master_netdev=opts.master_netdev,
808 f38ea602 Iustin Pop
                                  reserved_lvs=opts.reserved_lvs)
809 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
810 90b6aa3a Manuel Franceschini
  return 0
811 90b6aa3a Manuel Franceschini
812 90b6aa3a Manuel Franceschini
813 3ccafd0e Iustin Pop
def QueueOps(opts, args):
814 3ccafd0e Iustin Pop
  """Queue operations.
815 3ccafd0e Iustin Pop

816 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
817 469ee405 Iustin Pop
  @type args: list
818 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
819 469ee405 Iustin Pop
  @rtype: int
820 469ee405 Iustin Pop
  @return: the desired exit code
821 469ee405 Iustin Pop

822 3ccafd0e Iustin Pop
  """
823 3ccafd0e Iustin Pop
  command = args[0]
824 3ccafd0e Iustin Pop
  client = GetClient()
825 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
826 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
827 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
828 3ccafd0e Iustin Pop
  elif command == "info":
829 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
830 3ccafd0e Iustin Pop
    if result[0]:
831 3a24c527 Iustin Pop
      val = "set"
832 3ccafd0e Iustin Pop
    else:
833 3a24c527 Iustin Pop
      val = "unset"
834 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
835 2e668b38 Guido Trotter
  else:
836 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
837 debac808 Iustin Pop
                               errors.ECODE_INVAL)
838 2e668b38 Guido Trotter
839 3ccafd0e Iustin Pop
  return 0
840 3ccafd0e Iustin Pop
841 95b2e626 Michael Hanselmann
842 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
843 28b498cd Michael Hanselmann
  if until is None or until < time.time():
844 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
845 28b498cd Michael Hanselmann
  else:
846 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
847 28b498cd Michael Hanselmann
848 28b498cd Michael Hanselmann
849 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
850 95b2e626 Michael Hanselmann
  """Watcher operations.
851 95b2e626 Michael Hanselmann

852 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
853 95b2e626 Michael Hanselmann
  @type args: list
854 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
855 95b2e626 Michael Hanselmann
  @rtype: int
856 95b2e626 Michael Hanselmann
  @return: the desired exit code
857 95b2e626 Michael Hanselmann

858 95b2e626 Michael Hanselmann
  """
859 95b2e626 Michael Hanselmann
  command = args[0]
860 95b2e626 Michael Hanselmann
  client = GetClient()
861 95b2e626 Michael Hanselmann
862 95b2e626 Michael Hanselmann
  if command == "continue":
863 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
864 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
865 95b2e626 Michael Hanselmann
866 95b2e626 Michael Hanselmann
  elif command == "pause":
867 95b2e626 Michael Hanselmann
    if len(args) < 2:
868 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
869 95b2e626 Michael Hanselmann
870 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
871 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
872 95b2e626 Michael Hanselmann
873 95b2e626 Michael Hanselmann
  elif command == "info":
874 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
875 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
876 95b2e626 Michael Hanselmann
877 95b2e626 Michael Hanselmann
  else:
878 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
879 debac808 Iustin Pop
                               errors.ECODE_INVAL)
880 95b2e626 Michael Hanselmann
881 95b2e626 Michael Hanselmann
  return 0
882 95b2e626 Michael Hanselmann
883 95b2e626 Michael Hanselmann
884 a8083063 Iustin Pop
commands = {
885 6ea815cf Iustin Pop
  'init': (
886 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
887 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
888 6ea815cf Iustin Pop
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
889 b989b9d9 Ken Wehr
     NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
890 39b0f0c2 Balazs Lecz
     SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
891 bf4af505 Apollon Oikonomopoulos
     UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
892 6204ee71 René Nussbaumer
     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
893 6204ee71 René Nussbaumer
     NODE_PARAMS_OPT],
894 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
895 6ea815cf Iustin Pop
  'destroy': (
896 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
897 6ea815cf Iustin Pop
    "", "Destroy cluster"),
898 6ea815cf Iustin Pop
  'rename': (
899 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
900 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
901 6ea815cf Iustin Pop
    "<new_name>",
902 6ea815cf Iustin Pop
    "Renames the cluster"),
903 6ea815cf Iustin Pop
  'redist-conf': (
904 aa06f8c6 Michael Hanselmann
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
905 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
906 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
907 6ea815cf Iustin Pop
  'verify': (
908 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
909 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
910 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
911 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
912 6ea815cf Iustin Pop
  'verify-disks': (
913 aa06f8c6 Michael Hanselmann
    VerifyDisks, ARGS_NONE, [PRIORITY_OPT],
914 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
915 6ea815cf Iustin Pop
  'repair-disk-sizes': (
916 aa06f8c6 Michael Hanselmann
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
917 6ea815cf Iustin Pop
    "", "Updates mismatches in recorded disk sizes"),
918 c28502b1 Iustin Pop
  'master-failover': (
919 064c21f8 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT],
920 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
921 4404ffad Iustin Pop
  'master-ping': (
922 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
923 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
924 6ea815cf Iustin Pop
  'version': (
925 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
926 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
927 6ea815cf Iustin Pop
  'getmaster': (
928 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
929 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
930 6ea815cf Iustin Pop
  'copyfile': (
931 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
932 74adc100 Iustin Pop
    [NODE_LIST_OPT, USE_REPL_NET_OPT],
933 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
934 6ea815cf Iustin Pop
  'command': (
935 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
936 064c21f8 Iustin Pop
    [NODE_LIST_OPT],
937 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
938 6ea815cf Iustin Pop
  'info': (
939 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
940 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
941 6ea815cf Iustin Pop
  'list-tags': (
942 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
943 6ea815cf Iustin Pop
  'add-tags': (
944 aa06f8c6 Michael Hanselmann
    AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
945 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
946 6ea815cf Iustin Pop
  'remove-tags': (
947 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
948 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
949 6ea815cf Iustin Pop
  'search-tags': (
950 aa06f8c6 Michael Hanselmann
    SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "",
951 aa06f8c6 Michael Hanselmann
    "Searches the tags on all objects on"
952 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
953 6ea815cf Iustin Pop
  'queue': (
954 6ea815cf Iustin Pop
    QueueOps,
955 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
956 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
957 6ea815cf Iustin Pop
  'watcher': (
958 6ea815cf Iustin Pop
    WatcherOps,
959 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
960 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
961 064c21f8 Iustin Pop
    [],
962 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
963 6ea815cf Iustin Pop
  'modify': (
964 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
965 38f9d2cf Guido Trotter
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
966 1338f2b4 Balazs Lecz
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
967 ed14ed48 Luca Bigliardi
     UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT,
968 db5a8a2d Iustin Pop
     NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, RESERVED_LVS_OPT,
969 6204ee71 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT, NODE_PARAMS_OPT],
970 6ea815cf Iustin Pop
    "[opts...]",
971 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
972 6d4a1656 Michael Hanselmann
  "renew-crypto": (
973 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
974 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
975 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
976 3db3eb2a Michael Hanselmann
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT],
977 6d4a1656 Michael Hanselmann
    "[opts...]",
978 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
979 a8083063 Iustin Pop
  }
980 a8083063 Iustin Pop
981 6d4a1656 Michael Hanselmann
982 c28502b1 Iustin Pop
#: dictionary with aliases for commands
983 c28502b1 Iustin Pop
aliases = {
984 c28502b1 Iustin Pop
  'masterfailover': 'master-failover',
985 c28502b1 Iustin Pop
}
986 c28502b1 Iustin Pop
987 c28502b1 Iustin Pop
988 7b3e7d41 Michael Hanselmann
def Main():
989 7b3e7d41 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
990 7b3e7d41 Michael Hanselmann
                     aliases=aliases)