Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ f36c3e2d

History | View | Annotate | Download (31 kB)

1 7b3e7d41 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 afc3c260 Iustin Pop
# Copyright (C) 2006, 2007, 2010, 2011 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 afc3c260 Iustin Pop
  ToStdout("Hidden OSes: %s", utils.CommaJoin(result["hidden_os"]))
325 afc3c260 Iustin Pop
  ToStdout("Blacklisted OSes: %s", utils.CommaJoin(result["blacklisted_os"]))
326 afc3c260 Iustin Pop
327 3a24c527 Iustin Pop
  ToStdout("Cluster parameters:")
328 d729e03a Guido Trotter
  ToStdout("  - candidate pool size: %s",
329 d729e03a Guido Trotter
            compat.TryToRoman(result["candidate_pool_size"],
330 d729e03a Guido Trotter
                              convert=opts.roman_integers))
331 a8001106 Guido Trotter
  ToStdout("  - master netdev: %s", result["master_netdev"])
332 a8001106 Guido Trotter
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
333 5a3ab484 Iustin Pop
  if result["reserved_lvs"]:
334 5a3ab484 Iustin Pop
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
335 5a3ab484 Iustin Pop
  else:
336 5a3ab484 Iustin Pop
    reserved_lvs = "(none)"
337 5a3ab484 Iustin Pop
  ToStdout("  - lvm reserved volumes: %s", reserved_lvs)
338 ed14ed48 Luca Bigliardi
  ToStdout("  - drbd usermode helper: %s", result["drbd_usermode_helper"])
339 a8001106 Guido Trotter
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
340 3953242f Iustin Pop
  ToStdout("  - maintenance of node health: %s",
341 3953242f Iustin Pop
           result["maintain_node_health"])
342 d729e03a Guido Trotter
  ToStdout("  - uid pool: %s",
343 d729e03a Guido Trotter
            uidpool.FormatUidPool(result["uid_pool"],
344 d729e03a Guido Trotter
                                  roman=opts.roman_integers))
345 bf4af505 Apollon Oikonomopoulos
  ToStdout("  - default instance allocator: %s", result["default_iallocator"])
346 e7323b5e Manuel Franceschini
  ToStdout("  - primary ip version: %d", result["primary_ip_version"])
347 b18ecea2 René Nussbaumer
  ToStdout("  - preallocation wipe disks: %s", result["prealloc_wipe_disks"])
348 f36c3e2d Ben Lipton
  ToStdout("  - OS search path: %s", utils.CommaJoin(constants.OS_SEARCH_PATH))
349 4b7735f9 Iustin Pop
350 88be69ee René Nussbaumer
  ToStdout("Default node parameters:")
351 88be69ee René Nussbaumer
  _PrintGroupedParams(result["ndparams"], roman=opts.roman_integers)
352 88be69ee René Nussbaumer
353 4b7735f9 Iustin Pop
  ToStdout("Default instance parameters:")
354 d729e03a Guido Trotter
  _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
355 1094acda Guido Trotter
356 1094acda Guido Trotter
  ToStdout("Default nic parameters:")
357 d729e03a Guido Trotter
  _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers)
358 8a12ce45 Iustin Pop
359 a8083063 Iustin Pop
  return 0
360 a8083063 Iustin Pop
361 a8083063 Iustin Pop
362 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
363 a8083063 Iustin Pop
  """Copy a file from master to 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 only one element, the path of
368 469ee405 Iustin Pop
      the file to be copied
369 469ee405 Iustin Pop
  @rtype: int
370 469ee405 Iustin Pop
  @return: the desired exit code
371 a8083063 Iustin Pop

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

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

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

432 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
433 469ee405 Iustin Pop
  @type args: list
434 469ee405 Iustin Pop
  @param args: should be an empty list
435 469ee405 Iustin Pop
  @rtype: int
436 469ee405 Iustin Pop
  @return: the desired exit code
437 a8083063 Iustin Pop

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

455 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
456 469ee405 Iustin Pop
  @type args: list
457 469ee405 Iustin Pop
  @param args: should be an empty list
458 469ee405 Iustin Pop
  @rtype: int
459 469ee405 Iustin Pop
  @return: the desired exit code
460 f4d4e184 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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