Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 9a914f7a

History | View | Annotate | Download (30.9 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 4b7735f9 Iustin Pop
349 88be69ee René Nussbaumer
  ToStdout("Default node parameters:")
350 88be69ee René Nussbaumer
  _PrintGroupedParams(result["ndparams"], roman=opts.roman_integers)
351 88be69ee René Nussbaumer
352 4b7735f9 Iustin Pop
  ToStdout("Default instance parameters:")
353 d729e03a Guido Trotter
  _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
354 1094acda Guido Trotter
355 1094acda Guido Trotter
  ToStdout("Default nic parameters:")
356 d729e03a Guido Trotter
  _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers)
357 8a12ce45 Iustin Pop
358 a8083063 Iustin Pop
  return 0
359 a8083063 Iustin Pop
360 a8083063 Iustin Pop
361 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
362 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
363 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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