Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ b6267745

History | View | Annotate | Download (45.6 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 b459a848 Andrea Spadaccini
# pylint: disable=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 66d1f035 René Nussbaumer
import itertools
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti.cli import *
35 a8083063 Iustin Pop
from ganeti import opcodes
36 c2a62a33 Michael Hanselmann
from ganeti import constants
37 f4d4e184 Iustin Pop
from ganeti import errors
38 b63ed789 Iustin Pop
from ganeti import utils
39 a0c9f010 Michael Hanselmann
from ganeti import bootstrap
40 b3989551 Iustin Pop
from ganeti import ssh
41 d3cfe525 Guido Trotter
from ganeti import objects
42 1338f2b4 Balazs Lecz
from ganeti import uidpool
43 cea881e5 Michael Hanselmann
from ganeti import compat
44 66d1f035 René Nussbaumer
from ganeti import netutils
45 66d1f035 René Nussbaumer
46 66d1f035 René Nussbaumer
47 66d1f035 René Nussbaumer
ON_OPT = cli_option("--on", default=False,
48 66d1f035 René Nussbaumer
                    action="store_true", dest="on",
49 66d1f035 René Nussbaumer
                    help="Recover from an EPO")
50 66d1f035 René Nussbaumer
51 66d1f035 René Nussbaumer
GROUPS_OPT = cli_option("--groups", default=False,
52 66d1f035 René Nussbaumer
                    action="store_true", dest="groups",
53 66d1f035 René Nussbaumer
                    help="Arguments are node groups instead of nodes")
54 66d1f035 René Nussbaumer
55 66d1f035 René Nussbaumer
_EPO_PING_INTERVAL = 30 # 30 seconds between pings
56 66d1f035 René Nussbaumer
_EPO_PING_TIMEOUT = 1 # 1 second
57 66d1f035 René Nussbaumer
_EPO_REACHABLE_TIMEOUT = 15 * 60 # 15 minutes
58 a8083063 Iustin Pop
59 a8083063 Iustin Pop
60 4331f6cd Michael Hanselmann
@UsesRPC
61 a8083063 Iustin Pop
def InitCluster(opts, args):
62 a8083063 Iustin Pop
  """Initialize the cluster.
63 a8083063 Iustin Pop

64 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
65 469ee405 Iustin Pop
  @type args: list
66 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
67 469ee405 Iustin Pop
      cluster name
68 469ee405 Iustin Pop
  @rtype: int
69 469ee405 Iustin Pop
  @return: the desired exit code
70 a8083063 Iustin Pop

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

173 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
174 469ee405 Iustin Pop
  @type args: list
175 469ee405 Iustin Pop
  @param args: should be an empty list
176 469ee405 Iustin Pop
  @rtype: int
177 469ee405 Iustin Pop
  @return: the desired exit code
178 098c0958 Michael Hanselmann

179 a8083063 Iustin Pop
  """
180 a8083063 Iustin Pop
  if not opts.yes_do_it:
181 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
182 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
183 a8083063 Iustin Pop
    return 1
184 a8083063 Iustin Pop
185 c6d43e9e Iustin Pop
  op = opcodes.OpClusterDestroy()
186 400ca2f7 Iustin Pop
  master = SubmitOpCode(op, opts=opts)
187 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
188 140aa4a8 Iustin Pop
  # shutdown all the daemons
189 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
190 a8083063 Iustin Pop
  return 0
191 a8083063 Iustin Pop
192 a8083063 Iustin Pop
193 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
194 07bd8a51 Iustin Pop
  """Rename the cluster.
195 07bd8a51 Iustin Pop

196 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
197 469ee405 Iustin Pop
  @type args: list
198 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
199 469ee405 Iustin Pop
  @rtype: int
200 469ee405 Iustin Pop
  @return: the desired exit code
201 07bd8a51 Iustin Pop

202 07bd8a51 Iustin Pop
  """
203 6a016df9 Michael Hanselmann
  cl = GetClient()
204 6a016df9 Michael Hanselmann
205 6a016df9 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
206 6a016df9 Michael Hanselmann
207 6a016df9 Michael Hanselmann
  new_name = args[0]
208 07bd8a51 Iustin Pop
  if not opts.force:
209 6a016df9 Michael Hanselmann
    usertext = ("This will rename the cluster from '%s' to '%s'. If you are"
210 6a016df9 Michael Hanselmann
                " connected over the network to the cluster name, the"
211 6a016df9 Michael Hanselmann
                " operation is very dangerous as the IP address will be"
212 6a016df9 Michael Hanselmann
                " removed from the node and the change may not go through."
213 6a016df9 Michael Hanselmann
                " Continue?") % (cluster_name, new_name)
214 47988778 Iustin Pop
    if not AskUser(usertext):
215 07bd8a51 Iustin Pop
      return 1
216 07bd8a51 Iustin Pop
217 e126df25 Iustin Pop
  op = opcodes.OpClusterRename(name=new_name)
218 6a016df9 Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
219 6a016df9 Michael Hanselmann
220 48418fea Iustin Pop
  if result:
221 48418fea Iustin Pop
    ToStdout("Cluster renamed from '%s' to '%s'", cluster_name, result)
222 6a016df9 Michael Hanselmann
223 07bd8a51 Iustin Pop
  return 0
224 07bd8a51 Iustin Pop
225 07bd8a51 Iustin Pop
226 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
227 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
228 afee0879 Iustin Pop

229 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
230 afee0879 Iustin Pop
  @type args: list
231 afee0879 Iustin Pop
  @param args: empty list
232 afee0879 Iustin Pop
  @rtype: int
233 afee0879 Iustin Pop
  @return: the desired exit code
234 afee0879 Iustin Pop

235 afee0879 Iustin Pop
  """
236 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
237 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
238 afee0879 Iustin Pop
  return 0
239 afee0879 Iustin Pop
240 afee0879 Iustin Pop
241 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
242 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
243 a8083063 Iustin Pop

244 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
245 469ee405 Iustin Pop
  @type args: list
246 469ee405 Iustin Pop
  @param args: should be an empty list
247 469ee405 Iustin Pop
  @rtype: int
248 469ee405 Iustin Pop
  @return: the desired exit code
249 a8083063 Iustin Pop

250 a8083063 Iustin Pop
  """
251 2e7b8369 Iustin Pop
  cl = GetClient()
252 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
253 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
254 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
255 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
256 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
257 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
258 a8083063 Iustin Pop
  return 0
259 a8083063 Iustin Pop
260 a8083063 Iustin Pop
261 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
262 a8083063 Iustin Pop
  """Write name of master node to the standard output.
263 a8083063 Iustin Pop

264 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
265 469ee405 Iustin Pop
  @type args: list
266 469ee405 Iustin Pop
  @param args: should be an empty list
267 469ee405 Iustin Pop
  @rtype: int
268 469ee405 Iustin Pop
  @return: the desired exit code
269 a8083063 Iustin Pop

270 a8083063 Iustin Pop
  """
271 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
272 8eb148ae Iustin Pop
  ToStdout(master)
273 a8083063 Iustin Pop
  return 0
274 a8083063 Iustin Pop
275 cac599f1 Michael Hanselmann
276 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
277 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
278 1094acda Guido Trotter

279 1094acda Guido Trotter
  @type paramsdict: dict of dicts
280 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
281 664a9d73 René Nussbaumer
  @type level: int
282 664a9d73 René Nussbaumer
  @param level: Level of indention
283 1094acda Guido Trotter

284 1094acda Guido Trotter
  """
285 664a9d73 René Nussbaumer
  indent = "  " * level
286 9d91c6ab Guido Trotter
  for item, val in sorted(paramsdict.items()):
287 664a9d73 René Nussbaumer
    if isinstance(val, dict):
288 664a9d73 René Nussbaumer
      ToStdout("%s- %s:", indent, item)
289 d729e03a Guido Trotter
      _PrintGroupedParams(val, level=level + 1, roman=roman)
290 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
291 d729e03a Guido Trotter
      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
292 664a9d73 René Nussbaumer
    else:
293 664a9d73 René Nussbaumer
      ToStdout("%s  %s: %s", indent, item, val)
294 a8083063 Iustin Pop
295 cac599f1 Michael Hanselmann
296 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
297 a8083063 Iustin Pop
  """Shows cluster information.
298 a8083063 Iustin Pop

299 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
300 469ee405 Iustin Pop
  @type args: list
301 469ee405 Iustin Pop
  @param args: should be an empty list
302 469ee405 Iustin Pop
  @rtype: int
303 469ee405 Iustin Pop
  @return: the desired exit code
304 469ee405 Iustin Pop

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

383 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
384 469ee405 Iustin Pop
  @type args: list
385 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
386 469ee405 Iustin Pop
      the file to be copied
387 469ee405 Iustin Pop
  @rtype: int
388 469ee405 Iustin Pop
  @return: the desired exit code
389 a8083063 Iustin Pop

390 a8083063 Iustin Pop
  """
391 b3989551 Iustin Pop
  filename = args[0]
392 b3989551 Iustin Pop
  if not os.path.exists(filename):
393 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
394 debac808 Iustin Pop
                               errors.ECODE_INVAL)
395 b3989551 Iustin Pop
396 56bece1f Iustin Pop
  cl = GetClient()
397 56bece1f Iustin Pop
398 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
399 56bece1f Iustin Pop
400 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
401 b6e88032 Michael Hanselmann
                           secondary_ips=opts.use_replication_network,
402 b6e88032 Michael Hanselmann
                           nodegroup=opts.nodegroup)
403 e00ea635 Michael Hanselmann
404 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
405 b3989551 Iustin Pop
  for node in results:
406 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
407 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
408 b3989551 Iustin Pop
409 a8083063 Iustin Pop
  return 0
410 a8083063 Iustin Pop
411 a8083063 Iustin Pop
412 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
413 a8083063 Iustin Pop
  """Run a command on some nodes.
414 a8083063 Iustin Pop

415 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
416 469ee405 Iustin Pop
  @type args: list
417 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
418 469ee405 Iustin Pop
  @rtype: int
419 469ee405 Iustin Pop
  @return: the desired exit code
420 a8083063 Iustin Pop

421 a8083063 Iustin Pop
  """
422 56bece1f Iustin Pop
  cl = GetClient()
423 7688d0d3 Michael Hanselmann
424 a8083063 Iustin Pop
  command = " ".join(args)
425 4040a784 Iustin Pop
426 b6e88032 Michael Hanselmann
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl, nodegroup=opts.nodegroup)
427 56bece1f Iustin Pop
428 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
429 56bece1f Iustin Pop
                                                    "master_node"])
430 b3989551 Iustin Pop
431 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
432 b3989551 Iustin Pop
433 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
434 b3989551 Iustin Pop
  if master_node in nodes:
435 b3989551 Iustin Pop
    nodes.remove(master_node)
436 b3989551 Iustin Pop
    nodes.append(master_node)
437 b3989551 Iustin Pop
438 b3989551 Iustin Pop
  for name in nodes:
439 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
440 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
441 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
442 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
443 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
444 b3989551 Iustin Pop
445 b3989551 Iustin Pop
  return 0
446 a8083063 Iustin Pop
447 a8083063 Iustin Pop
448 a8083063 Iustin Pop
def VerifyCluster(opts, args):
449 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
450 a8083063 Iustin Pop

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

457 a8083063 Iustin Pop
  """
458 8d59409f Iustin Pop
  skip_checks = []
459 bf93ae69 Adeodato Simo
460 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
461 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
462 bf93ae69 Adeodato Simo
463 fcad7225 Michael Hanselmann
  cl = GetClient()
464 bf93ae69 Adeodato Simo
465 fcad7225 Michael Hanselmann
  op = opcodes.OpClusterVerify(verbose=opts.verbose,
466 fcad7225 Michael Hanselmann
                               error_codes=opts.error_codes,
467 fcad7225 Michael Hanselmann
                               debug_simulate_errors=opts.simulate_errors,
468 fcad7225 Michael Hanselmann
                               skip_checks=skip_checks,
469 fcad7225 Michael Hanselmann
                               group_name=opts.nodegroup)
470 fcad7225 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
471 bf93ae69 Adeodato Simo
472 fcad7225 Michael Hanselmann
  # Keep track of submitted jobs
473 fcad7225 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
474 fcad7225 Michael Hanselmann
475 fcad7225 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
476 fcad7225 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
477 bf93ae69 Adeodato Simo
478 fcad7225 Michael Hanselmann
  results = jex.GetResults()
479 ebe6cf38 Michael Hanselmann
480 ebe6cf38 Michael Hanselmann
  (bad_jobs, bad_results) = \
481 ebe6cf38 Michael Hanselmann
    map(len,
482 ebe6cf38 Michael Hanselmann
        # Convert iterators to lists
483 ebe6cf38 Michael Hanselmann
        map(list,
484 ebe6cf38 Michael Hanselmann
            # Count errors
485 ebe6cf38 Michael Hanselmann
            map(compat.partial(itertools.ifilterfalse, bool),
486 ebe6cf38 Michael Hanselmann
                # Convert result to booleans in a tuple
487 ebe6cf38 Michael Hanselmann
                zip(*((job_success, len(op_results) == 1 and op_results[0])
488 ebe6cf38 Michael Hanselmann
                      for (job_success, op_results) in results)))))
489 ebe6cf38 Michael Hanselmann
490 ebe6cf38 Michael Hanselmann
  if bad_jobs == 0 and bad_results == 0:
491 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
492 e0508c86 Guido Trotter
  else:
493 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
494 ebe6cf38 Michael Hanselmann
    if bad_jobs > 0:
495 ebe6cf38 Michael Hanselmann
      ToStdout("%s job(s) failed while verifying the cluster.", bad_jobs)
496 fcad7225 Michael Hanselmann
497 fcad7225 Michael Hanselmann
  return rcode
498 a8083063 Iustin Pop
499 a8083063 Iustin Pop
500 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
501 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
502 f4d4e184 Iustin Pop

503 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
504 469ee405 Iustin Pop
  @type args: list
505 469ee405 Iustin Pop
  @param args: should be an empty list
506 469ee405 Iustin Pop
  @rtype: int
507 469ee405 Iustin Pop
  @return: the desired exit code
508 f4d4e184 Iustin Pop

509 f4d4e184 Iustin Pop
  """
510 f1b083ce Michael Hanselmann
  cl = GetClient()
511 f1b083ce Michael Hanselmann
512 bd8210a7 Iustin Pop
  op = opcodes.OpClusterVerifyDisks()
513 f4d4e184 Iustin Pop
514 ae1a845c Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
515 ae1a845c Michael Hanselmann
516 ae1a845c Michael Hanselmann
  # Keep track of submitted jobs
517 ae1a845c Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
518 ae1a845c Michael Hanselmann
519 ae1a845c Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
520 ae1a845c Michael Hanselmann
    jex.AddJobId(None, status, job_id)
521 b63ed789 Iustin Pop
522 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
523 b63ed789 Iustin Pop
524 ae1a845c Michael Hanselmann
  for (status, result) in jex.GetResults():
525 ae1a845c Michael Hanselmann
    if not status:
526 ae1a845c Michael Hanselmann
      ToStdout("Job failed: %s", result)
527 ae1a845c Michael Hanselmann
      continue
528 ae1a845c Michael Hanselmann
529 ae1a845c Michael Hanselmann
    ((bad_nodes, instances, missing), ) = result
530 ae1a845c Michael Hanselmann
531 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
532 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
533 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
534 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
535 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
536 b63ed789 Iustin Pop
537 f4d4e184 Iustin Pop
    for iname in instances:
538 b63ed789 Iustin Pop
      if iname in missing:
539 b63ed789 Iustin Pop
        continue
540 83f5d475 Iustin Pop
      op = opcodes.OpInstanceActivateDisks(instance_name=iname)
541 f4d4e184 Iustin Pop
      try:
542 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
543 f1b083ce Michael Hanselmann
        SubmitOpCode(op, opts=opts, cl=cl)
544 f4d4e184 Iustin Pop
      except errors.GenericError, err:
545 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
546 f4d4e184 Iustin Pop
        retcode |= nret
547 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
548 b63ed789 Iustin Pop
549 ae1a845c Michael Hanselmann
    if missing:
550 ae1a845c Michael Hanselmann
      for iname, ival in missing.iteritems():
551 ae1a845c Michael Hanselmann
        all_missing = compat.all(x[0] in bad_nodes for x in ival)
552 ae1a845c Michael Hanselmann
        if all_missing:
553 ae1a845c Michael Hanselmann
          ToStdout("Instance %s cannot be verified as it lives on"
554 ae1a845c Michael Hanselmann
                   " broken nodes", iname)
555 ae1a845c Michael Hanselmann
        else:
556 ae1a845c Michael Hanselmann
          ToStdout("Instance %s has missing logical volumes:", iname)
557 ae1a845c Michael Hanselmann
          ival.sort()
558 ae1a845c Michael Hanselmann
          for node, vol in ival:
559 ae1a845c Michael Hanselmann
            if node in bad_nodes:
560 ae1a845c Michael Hanselmann
              ToStdout("\tbroken node %s /dev/%s", node, vol)
561 ae1a845c Michael Hanselmann
            else:
562 ae1a845c Michael Hanselmann
              ToStdout("\t%s /dev/%s", node, vol)
563 ae1a845c Michael Hanselmann
564 ae1a845c Michael Hanselmann
      ToStdout("You need to replace or recreate disks for all the above"
565 ae1a845c Michael Hanselmann
               " instances if this message persists after fixing broken nodes.")
566 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
567 f4d4e184 Iustin Pop
568 f4d4e184 Iustin Pop
  return retcode
569 f4d4e184 Iustin Pop
570 f4d4e184 Iustin Pop
571 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
572 60975797 Iustin Pop
  """Verify sizes of cluster disks.
573 60975797 Iustin Pop

574 60975797 Iustin Pop
  @param opts: the command line options selected by the user
575 60975797 Iustin Pop
  @type args: list
576 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
577 60975797 Iustin Pop
  @rtype: int
578 60975797 Iustin Pop
  @return: the desired exit code
579 60975797 Iustin Pop

580 60975797 Iustin Pop
  """
581 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
582 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
583 60975797 Iustin Pop
584 60975797 Iustin Pop
585 4331f6cd Michael Hanselmann
@UsesRPC
586 a8083063 Iustin Pop
def MasterFailover(opts, args):
587 a8083063 Iustin Pop
  """Failover the master node.
588 a8083063 Iustin Pop

589 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
590 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
591 a8083063 Iustin Pop
  master.
592 a8083063 Iustin Pop

593 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
594 469ee405 Iustin Pop
  @type args: list
595 469ee405 Iustin Pop
  @param args: should be an empty list
596 469ee405 Iustin Pop
  @rtype: int
597 469ee405 Iustin Pop
  @return: the desired exit code
598 469ee405 Iustin Pop

599 a8083063 Iustin Pop
  """
600 8e2524c3 Guido Trotter
  if opts.no_voting:
601 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
602 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
603 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
604 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
605 8e2524c3 Guido Trotter
    if not AskUser(usertext):
606 8e2524c3 Guido Trotter
      return 1
607 8e2524c3 Guido Trotter
608 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
609 a8083063 Iustin Pop
610 a8083063 Iustin Pop
611 4404ffad Iustin Pop
def MasterPing(opts, args):
612 4404ffad Iustin Pop
  """Checks if the master is alive.
613 4404ffad Iustin Pop

614 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
615 4404ffad Iustin Pop
  @type args: list
616 4404ffad Iustin Pop
  @param args: should be an empty list
617 4404ffad Iustin Pop
  @rtype: int
618 4404ffad Iustin Pop
  @return: the desired exit code
619 4404ffad Iustin Pop

620 4404ffad Iustin Pop
  """
621 4404ffad Iustin Pop
  try:
622 4404ffad Iustin Pop
    cl = GetClient()
623 4404ffad Iustin Pop
    cl.QueryClusterInfo()
624 4404ffad Iustin Pop
    return 0
625 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
626 4404ffad Iustin Pop
    return 1
627 4404ffad Iustin Pop
628 4404ffad Iustin Pop
629 73415719 Iustin Pop
def SearchTags(opts, args):
630 73415719 Iustin Pop
  """Searches the tags on all the cluster.
631 73415719 Iustin Pop

632 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
633 469ee405 Iustin Pop
  @type args: list
634 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
635 469ee405 Iustin Pop
  @rtype: int
636 469ee405 Iustin Pop
  @return: the desired exit code
637 469ee405 Iustin Pop

638 73415719 Iustin Pop
  """
639 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
640 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
641 73415719 Iustin Pop
  if not result:
642 73415719 Iustin Pop
    return 1
643 73415719 Iustin Pop
  result = list(result)
644 73415719 Iustin Pop
  result.sort()
645 73415719 Iustin Pop
  for path, tag in result:
646 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
647 73415719 Iustin Pop
648 73415719 Iustin Pop
649 b6267745 Andrea Spadaccini
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
650 b6267745 Andrea Spadaccini
  """Reads and verifies an X509 certificate.
651 b6267745 Andrea Spadaccini

652 b6267745 Andrea Spadaccini
  @type cert_filename: string
653 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
654 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
655 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
656 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
657 b6267745 Andrea Spadaccini
                             the public certificate
658 b6267745 Andrea Spadaccini
  @rtype: string
659 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
660 b6267745 Andrea Spadaccini

661 b6267745 Andrea Spadaccini
  """
662 b6267745 Andrea Spadaccini
  try:
663 b6267745 Andrea Spadaccini
    pem = utils.ReadFile(cert_filename)
664 b6267745 Andrea Spadaccini
  except IOError, err:
665 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
666 b6267745 Andrea Spadaccini
                               "Unable to read certificate: %s" % str(err))
667 b6267745 Andrea Spadaccini
668 b6267745 Andrea Spadaccini
  try:
669 b6267745 Andrea Spadaccini
    OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
670 b6267745 Andrea Spadaccini
  except Exception, err:
671 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
672 b6267745 Andrea Spadaccini
                               "Unable to load certificate: %s" % str(err))
673 b6267745 Andrea Spadaccini
674 b6267745 Andrea Spadaccini
  if verify_private_key:
675 b6267745 Andrea Spadaccini
    try:
676 b6267745 Andrea Spadaccini
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, pem)
677 b6267745 Andrea Spadaccini
    except Exception, err:
678 b6267745 Andrea Spadaccini
      raise errors.X509CertError(cert_filename,
679 b6267745 Andrea Spadaccini
                                 "Unable to load private key: %s" % str(err))
680 b6267745 Andrea Spadaccini
681 b6267745 Andrea Spadaccini
  return pem
682 b6267745 Andrea Spadaccini
683 b6267745 Andrea Spadaccini
684 b6267745 Andrea Spadaccini
def _RenewCrypto(new_cluster_cert, new_rapi_cert, #pylint: disable=R0911
685 b6267745 Andrea Spadaccini
                 rapi_cert_filename, new_spice_cert, spice_cert_filename,
686 b6267745 Andrea Spadaccini
                 spice_cacert_filename, new_confd_hmac_key, new_cds,
687 b6267745 Andrea Spadaccini
                 cds_filename, force):
688 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
689 6d4a1656 Michael Hanselmann

690 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
691 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
692 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
693 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
694 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
695 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
696 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
697 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
698 b6267745 Andrea Spadaccini
  @type spice_cert_filename: string
699 b6267745 Andrea Spadaccini
  @param spice_cert_filename: Path to file containing new SPICE certificate
700 b6267745 Andrea Spadaccini
  @type spice_cacert_filename: string
701 b6267745 Andrea Spadaccini
  @param spice_cacert_filename: Path to file containing the certificate of the
702 b6267745 Andrea Spadaccini
                                CA that signed the SPICE certificate
703 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
704 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
705 3db3eb2a Michael Hanselmann
  @type new_cds: bool
706 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
707 3db3eb2a Michael Hanselmann
  @type cds_filename: string
708 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
709 6d4a1656 Michael Hanselmann
  @type force: bool
710 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
711 6d4a1656 Michael Hanselmann

712 6d4a1656 Michael Hanselmann
  """
713 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
714 6e060e15 Andrea Spadaccini
    ToStderr("Only one of the --new-rapi-certificate and --rapi-certificate"
715 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
716 6d4a1656 Michael Hanselmann
    return 1
717 6d4a1656 Michael Hanselmann
718 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
719 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
720 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
721 3db3eb2a Michael Hanselmann
             " the same time.")
722 3db3eb2a Michael Hanselmann
    return 1
723 3db3eb2a Michael Hanselmann
724 b6267745 Andrea Spadaccini
  if new_spice_cert and (spice_cert_filename or spice_cacert_filename):
725 b6267745 Andrea Spadaccini
    ToStderr("When using --new-spice-certificate, the --spice-certificate"
726 b6267745 Andrea Spadaccini
             " and --spice-ca-certificate must not be used.")
727 b6267745 Andrea Spadaccini
    return 1
728 6d4a1656 Michael Hanselmann
729 b6267745 Andrea Spadaccini
  if bool(spice_cacert_filename) ^ bool(spice_cert_filename):
730 b6267745 Andrea Spadaccini
    ToStderr("Both --spice-certificate and --spice-ca-certificate must be"
731 b6267745 Andrea Spadaccini
             " specified.")
732 b6267745 Andrea Spadaccini
    return 1
733 6d4a1656 Michael Hanselmann
734 b6267745 Andrea Spadaccini
  rapi_cert_pem, spice_cert_pem, spice_cacert_pem = (None, None, None)
735 b6267745 Andrea Spadaccini
  try:
736 b6267745 Andrea Spadaccini
    if rapi_cert_filename:
737 b6267745 Andrea Spadaccini
      rapi_cert_pem = _ReadAndVerifyCert(rapi_cert_filename, True)
738 b6267745 Andrea Spadaccini
    if spice_cert_filename:
739 b6267745 Andrea Spadaccini
      spice_cert_pem = _ReadAndVerifyCert(spice_cert_filename, True)
740 b6267745 Andrea Spadaccini
      spice_cacert_pem = _ReadAndVerifyCert(spice_cacert_filename)
741 b6267745 Andrea Spadaccini
  except errors.X509CertError, err:
742 b6267745 Andrea Spadaccini
    ToStderr("Unable to load X509 certificate from %s: %s", err[0], err[1])
743 b6267745 Andrea Spadaccini
    return 1
744 6d4a1656 Michael Hanselmann
745 3db3eb2a Michael Hanselmann
  if cds_filename:
746 3db3eb2a Michael Hanselmann
    try:
747 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
748 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
749 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
750 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
751 3db3eb2a Michael Hanselmann
      return 1
752 3db3eb2a Michael Hanselmann
  else:
753 3db3eb2a Michael Hanselmann
    cds = None
754 3db3eb2a Michael Hanselmann
755 6d4a1656 Michael Hanselmann
  if not force:
756 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
757 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
758 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
759 6d4a1656 Michael Hanselmann
      return 1
760 6d4a1656 Michael Hanselmann
761 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
762 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
763 b6267745 Andrea Spadaccini
    bootstrap.GenerateClusterCrypto(new_cluster_cert,
764 b6267745 Andrea Spadaccini
                                    new_rapi_cert,
765 b6267745 Andrea Spadaccini
                                    new_spice_cert,
766 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
767 3db3eb2a Michael Hanselmann
                                    new_cds,
768 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
769 b6267745 Andrea Spadaccini
                                    spice_cert_pem=spice_cert_pem,
770 b6267745 Andrea Spadaccini
                                    spice_cacert_pem=spice_cacert_pem,
771 3db3eb2a Michael Hanselmann
                                    cds=cds)
772 6d4a1656 Michael Hanselmann
773 6d4a1656 Michael Hanselmann
    files_to_copy = []
774 6d4a1656 Michael Hanselmann
775 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
776 168c1de2 Michael Hanselmann
      files_to_copy.append(constants.NODED_CERT_FILE)
777 6d4a1656 Michael Hanselmann
778 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
779 6d4a1656 Michael Hanselmann
      files_to_copy.append(constants.RAPI_CERT_FILE)
780 6d4a1656 Michael Hanselmann
781 b6267745 Andrea Spadaccini
    if new_spice_cert or spice_cert_pem:
782 b6267745 Andrea Spadaccini
      files_to_copy.append(constants.SPICE_CERT_FILE)
783 b6267745 Andrea Spadaccini
      files_to_copy.append(constants.SPICE_CACERT_FILE)
784 b6267745 Andrea Spadaccini
785 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
786 6b7d5878 Michael Hanselmann
      files_to_copy.append(constants.CONFD_HMAC_KEY)
787 6d4a1656 Michael Hanselmann
788 3db3eb2a Michael Hanselmann
    if new_cds or cds:
789 3db3eb2a Michael Hanselmann
      files_to_copy.append(constants.CLUSTER_DOMAIN_SECRET_FILE)
790 3db3eb2a Michael Hanselmann
791 6d4a1656 Michael Hanselmann
    if files_to_copy:
792 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
793 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
794 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
795 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
796 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
797 6d4a1656 Michael Hanselmann
798 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
799 6d4a1656 Michael Hanselmann
800 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
801 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
802 6d4a1656 Michael Hanselmann
803 6d4a1656 Michael Hanselmann
  return 0
804 6d4a1656 Michael Hanselmann
805 6d4a1656 Michael Hanselmann
806 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
807 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
808 6d4a1656 Michael Hanselmann

809 6d4a1656 Michael Hanselmann
  """
810 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
811 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
812 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
813 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
814 b6267745 Andrea Spadaccini
                      opts.spice_cert,
815 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
816 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
817 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
818 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
819 6d4a1656 Michael Hanselmann
                      opts.force)
820 6d4a1656 Michael Hanselmann
821 6d4a1656 Michael Hanselmann
822 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
823 90b6aa3a Manuel Franceschini
  """Modify the cluster.
824 90b6aa3a Manuel Franceschini

825 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
826 469ee405 Iustin Pop
  @type args: list
827 469ee405 Iustin Pop
  @param args: should be an empty list
828 469ee405 Iustin Pop
  @rtype: int
829 469ee405 Iustin Pop
  @return: the desired exit code
830 90b6aa3a Manuel Franceschini

831 90b6aa3a Manuel Franceschini
  """
832 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
833 ed14ed48 Luca Bigliardi
          not opts.drbd_storage or opts.drbd_helper or
834 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
835 6204ee71 René Nussbaumer
          opts.beparams or opts.nicparams or opts.ndparams or
836 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
837 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
838 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
839 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
840 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
841 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
842 b883637f René Nussbaumer
          opts.reserved_lvs is not None or
843 38f9d2cf Guido Trotter
          opts.master_netdev is not None or
844 b883637f René Nussbaumer
          opts.prealloc_wipe_disks is not None):
845 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
846 90b6aa3a Manuel Franceschini
    return 1
847 90b6aa3a Manuel Franceschini
848 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
849 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
850 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
851 90b6aa3a Manuel Franceschini
    return 1
852 6d4a1656 Michael Hanselmann
853 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
854 6d4a1656 Michael Hanselmann
    vg_name = ""
855 90b6aa3a Manuel Franceschini
856 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
857 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
858 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
859 ed14ed48 Luca Bigliardi
    return 1
860 ed14ed48 Luca Bigliardi
861 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage:
862 ed14ed48 Luca Bigliardi
    drbd_helper = ""
863 ed14ed48 Luca Bigliardi
864 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
865 779c15bb Iustin Pop
  if hvlist is not None:
866 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
867 779c15bb Iustin Pop
868 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
869 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
870 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
871 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
872 779c15bb Iustin Pop
873 779c15bb Iustin Pop
  beparams = opts.beparams
874 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
875 779c15bb Iustin Pop
876 5af3da74 Guido Trotter
  nicparams = opts.nicparams
877 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
878 5af3da74 Guido Trotter
879 6204ee71 René Nussbaumer
  ndparams = opts.ndparams
880 6204ee71 René Nussbaumer
  if ndparams is not None:
881 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
882 1338f2b4 Balazs Lecz
883 3953242f Iustin Pop
  mnh = opts.maintain_node_health
884 3953242f Iustin Pop
885 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
886 1338f2b4 Balazs Lecz
  if uid_pool is not None:
887 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
888 1338f2b4 Balazs Lecz
889 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
890 fdad8c4d Balazs Lecz
  if add_uids is not None:
891 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
892 fdad8c4d Balazs Lecz
893 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
894 fdad8c4d Balazs Lecz
  if remove_uids is not None:
895 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
896 fdad8c4d Balazs Lecz
897 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
898 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
899 f38ea602 Iustin Pop
      opts.reserved_lvs = []
900 f38ea602 Iustin Pop
    else:
901 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
902 f38ea602 Iustin Pop
903 a6682fdc Iustin Pop
  op = opcodes.OpClusterSetParams(vg_name=vg_name,
904 ed14ed48 Luca Bigliardi
                                  drbd_helper=drbd_helper,
905 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
906 779c15bb Iustin Pop
                                  hvparams=hvparams,
907 17463d22 René Nussbaumer
                                  os_hvp=None,
908 4b7735f9 Iustin Pop
                                  beparams=beparams,
909 5af3da74 Guido Trotter
                                  nicparams=nicparams,
910 6204ee71 René Nussbaumer
                                  ndparams=ndparams,
911 3953242f Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size,
912 1338f2b4 Balazs Lecz
                                  maintain_node_health=mnh,
913 fdad8c4d Balazs Lecz
                                  uid_pool=uid_pool,
914 fdad8c4d Balazs Lecz
                                  add_uids=add_uids,
915 bf4af505 Apollon Oikonomopoulos
                                  remove_uids=remove_uids,
916 f38ea602 Iustin Pop
                                  default_iallocator=opts.default_iallocator,
917 b883637f René Nussbaumer
                                  prealloc_wipe_disks=opts.prealloc_wipe_disks,
918 38f9d2cf Guido Trotter
                                  master_netdev=opts.master_netdev,
919 f38ea602 Iustin Pop
                                  reserved_lvs=opts.reserved_lvs)
920 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
921 90b6aa3a Manuel Franceschini
  return 0
922 90b6aa3a Manuel Franceschini
923 90b6aa3a Manuel Franceschini
924 3ccafd0e Iustin Pop
def QueueOps(opts, args):
925 3ccafd0e Iustin Pop
  """Queue operations.
926 3ccafd0e Iustin Pop

927 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
928 469ee405 Iustin Pop
  @type args: list
929 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
930 469ee405 Iustin Pop
  @rtype: int
931 469ee405 Iustin Pop
  @return: the desired exit code
932 469ee405 Iustin Pop

933 3ccafd0e Iustin Pop
  """
934 3ccafd0e Iustin Pop
  command = args[0]
935 3ccafd0e Iustin Pop
  client = GetClient()
936 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
937 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
938 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
939 3ccafd0e Iustin Pop
  elif command == "info":
940 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
941 3ccafd0e Iustin Pop
    if result[0]:
942 3a24c527 Iustin Pop
      val = "set"
943 3ccafd0e Iustin Pop
    else:
944 3a24c527 Iustin Pop
      val = "unset"
945 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
946 2e668b38 Guido Trotter
  else:
947 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
948 debac808 Iustin Pop
                               errors.ECODE_INVAL)
949 2e668b38 Guido Trotter
950 3ccafd0e Iustin Pop
  return 0
951 3ccafd0e Iustin Pop
952 95b2e626 Michael Hanselmann
953 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
954 28b498cd Michael Hanselmann
  if until is None or until < time.time():
955 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
956 28b498cd Michael Hanselmann
  else:
957 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
958 28b498cd Michael Hanselmann
959 28b498cd Michael Hanselmann
960 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
961 95b2e626 Michael Hanselmann
  """Watcher operations.
962 95b2e626 Michael Hanselmann

963 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
964 95b2e626 Michael Hanselmann
  @type args: list
965 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
966 95b2e626 Michael Hanselmann
  @rtype: int
967 95b2e626 Michael Hanselmann
  @return: the desired exit code
968 95b2e626 Michael Hanselmann

969 95b2e626 Michael Hanselmann
  """
970 95b2e626 Michael Hanselmann
  command = args[0]
971 95b2e626 Michael Hanselmann
  client = GetClient()
972 95b2e626 Michael Hanselmann
973 95b2e626 Michael Hanselmann
  if command == "continue":
974 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
975 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
976 95b2e626 Michael Hanselmann
977 95b2e626 Michael Hanselmann
  elif command == "pause":
978 95b2e626 Michael Hanselmann
    if len(args) < 2:
979 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
980 95b2e626 Michael Hanselmann
981 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
982 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
983 95b2e626 Michael Hanselmann
984 95b2e626 Michael Hanselmann
  elif command == "info":
985 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
986 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
987 95b2e626 Michael Hanselmann
988 95b2e626 Michael Hanselmann
  else:
989 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
990 debac808 Iustin Pop
                               errors.ECODE_INVAL)
991 95b2e626 Michael Hanselmann
992 95b2e626 Michael Hanselmann
  return 0
993 95b2e626 Michael Hanselmann
994 95b2e626 Michael Hanselmann
995 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
996 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
997 66d1f035 René Nussbaumer

998 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
999 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on
1000 66d1f035 René Nussbaumer
  @param power: True if they should be powered on, False otherwise
1001 66d1f035 René Nussbaumer
  @return: The success of the operation (none failed)
1002 66d1f035 René Nussbaumer

1003 66d1f035 René Nussbaumer
  """
1004 66d1f035 René Nussbaumer
  if power:
1005 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
1006 66d1f035 René Nussbaumer
  else:
1007 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
1008 66d1f035 René Nussbaumer
1009 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
1010 66d1f035 René Nussbaumer
                            command=command,
1011 66d1f035 René Nussbaumer
                            ignore_status=True,
1012 cfed3b9f René Nussbaumer
                            timeout=opts.oob_timeout,
1013 cfed3b9f René Nussbaumer
                            power_delay=opts.power_delay)
1014 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
1015 66d1f035 René Nussbaumer
  errs = 0
1016 66d1f035 René Nussbaumer
  for node_result in result:
1017 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
1018 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
1019 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
1020 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
1021 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
1022 66d1f035 René Nussbaumer
      errs += 1
1023 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
1024 66d1f035 René Nussbaumer
               node_name)
1025 66d1f035 René Nussbaumer
1026 66d1f035 René Nussbaumer
  if errs > 0:
1027 66d1f035 René Nussbaumer
    return False
1028 66d1f035 René Nussbaumer
1029 66d1f035 René Nussbaumer
  return True
1030 66d1f035 René Nussbaumer
1031 66d1f035 René Nussbaumer
1032 66d1f035 René Nussbaumer
def _InstanceStart(opts, inst_list, start):
1033 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
1034 66d1f035 René Nussbaumer

1035 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1036 66d1f035 René Nussbaumer
  @param inst_list: The list of instances to operate on
1037 66d1f035 René Nussbaumer
  @param start: True if they should be started, False for shutdown
1038 66d1f035 René Nussbaumer
  @return: The success of the operation (none failed)
1039 66d1f035 René Nussbaumer

1040 66d1f035 René Nussbaumer
  """
1041 66d1f035 René Nussbaumer
  if start:
1042 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
1043 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
1044 66d1f035 René Nussbaumer
  else:
1045 fcecea0b René Nussbaumer
    opcls = compat.partial(opcodes.OpInstanceShutdown,
1046 fcecea0b René Nussbaumer
                           timeout=opts.shutdown_timeout)
1047 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
1048 66d1f035 René Nussbaumer
1049 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
1050 66d1f035 René Nussbaumer
1051 66d1f035 René Nussbaumer
  for inst in inst_list:
1052 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
1053 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
1054 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
1055 66d1f035 René Nussbaumer
1056 66d1f035 René Nussbaumer
  results = jex.GetResults()
1057 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
1058 66d1f035 René Nussbaumer
1059 66d1f035 René Nussbaumer
  if bad_cnt == 0:
1060 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
1061 66d1f035 René Nussbaumer
  else:
1062 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
1063 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
1064 66d1f035 René Nussbaumer
             len(results))
1065 66d1f035 René Nussbaumer
    return False
1066 66d1f035 René Nussbaumer
1067 66d1f035 René Nussbaumer
  return True
1068 66d1f035 René Nussbaumer
1069 66d1f035 René Nussbaumer
1070 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
1071 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
1072 66d1f035 René Nussbaumer

1073 66d1f035 René Nussbaumer
  @ivar success: Indicates if all action_cb calls were successful
1074 66d1f035 René Nussbaumer

1075 66d1f035 René Nussbaumer
  """
1076 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1077 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1078 66d1f035 René Nussbaumer
    """Init the object.
1079 66d1f035 René Nussbaumer

1080 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1081 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1082 66d1f035 René Nussbaumer
    @type node2ip: dict
1083 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1084 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1085 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1086 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1087 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1088 66d1f035 René Nussbaumer

1089 66d1f035 René Nussbaumer
    """
1090 66d1f035 René Nussbaumer
    self.down = set(node_list)
1091 66d1f035 René Nussbaumer
    self.up = set()
1092 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1093 66d1f035 René Nussbaumer
    self.success = True
1094 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1095 66d1f035 René Nussbaumer
    self.port = port
1096 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1097 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1098 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1099 66d1f035 René Nussbaumer
1100 66d1f035 René Nussbaumer
  def __call__(self):
1101 66d1f035 René Nussbaumer
    """When called we run action_cb.
1102 66d1f035 René Nussbaumer

1103 66d1f035 René Nussbaumer
    @raises utils.RetryAgain: When there are still down nodes
1104 66d1f035 René Nussbaumer

1105 66d1f035 René Nussbaumer
    """
1106 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1107 66d1f035 René Nussbaumer
      self.success = False
1108 66d1f035 René Nussbaumer
1109 66d1f035 René Nussbaumer
    if self.down:
1110 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1111 66d1f035 René Nussbaumer
    else:
1112 66d1f035 René Nussbaumer
      return self.success
1113 66d1f035 René Nussbaumer
1114 66d1f035 René Nussbaumer
  def Wait(self, secs):
1115 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1116 66d1f035 René Nussbaumer

1117 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1118 66d1f035 René Nussbaumer

1119 66d1f035 René Nussbaumer
    """
1120 66d1f035 René Nussbaumer
    start = time.time()
1121 66d1f035 René Nussbaumer
    for node in self.down:
1122 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1123 66d1f035 René Nussbaumer
                       live_port_needed=True):
1124 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1125 66d1f035 René Nussbaumer
        self.up.add(node)
1126 66d1f035 René Nussbaumer
        self.down -= self.up
1127 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1128 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1129 66d1f035 René Nussbaumer
        return
1130 66d1f035 René Nussbaumer
1131 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1132 66d1f035 René Nussbaumer
1133 66d1f035 René Nussbaumer
1134 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1135 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1136 66d1f035 René Nussbaumer

1137 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1138 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1139 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1140 66d1f035 René Nussbaumer

1141 66d1f035 René Nussbaumer
  """
1142 66d1f035 René Nussbaumer
  client = GetClient()
1143 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1144 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1145 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1146 66d1f035 René Nussbaumer
  else:
1147 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1148 66d1f035 René Nussbaumer
1149 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1150 66d1f035 René Nussbaumer
                 for node in node_list)
1151 66d1f035 René Nussbaumer
1152 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1153 8e74adce René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port,
1154 8e74adce René Nussbaumer
                                        ToStdout)
1155 66d1f035 René Nussbaumer
1156 66d1f035 René Nussbaumer
  try:
1157 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1158 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1159 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1160 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1161 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1162 66d1f035 René Nussbaumer
    return False
1163 66d1f035 René Nussbaumer
1164 66d1f035 René Nussbaumer
1165 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1166 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1167 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1168 66d1f035 René Nussbaumer

1169 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1170 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1171 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1172 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1173 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1174 66d1f035 René Nussbaumer

1175 66d1f035 René Nussbaumer
  """
1176 66d1f035 René Nussbaumer
  start_inst_list = []
1177 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1178 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1179 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1180 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1181 66d1f035 René Nussbaumer
1182 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1183 66d1f035 René Nussbaumer
    del inst_map[inst]
1184 66d1f035 René Nussbaumer
1185 66d1f035 René Nussbaumer
  if start_inst_list:
1186 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1187 66d1f035 René Nussbaumer
1188 66d1f035 René Nussbaumer
  return True
1189 66d1f035 René Nussbaumer
1190 66d1f035 René Nussbaumer
1191 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1192 66d1f035 René Nussbaumer
  """Does the actual power on.
1193 66d1f035 René Nussbaumer

1194 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1195 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1196 66d1f035 René Nussbaumer
                         OOB)
1197 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1198 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1199 66d1f035 René Nussbaumer
  @return: The desired exit status
1200 66d1f035 René Nussbaumer

1201 66d1f035 René Nussbaumer
  """
1202 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1203 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1204 66d1f035 René Nussbaumer
             " manually if needed")
1205 66d1f035 René Nussbaumer
1206 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1207 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1208 66d1f035 René Nussbaumer
1209 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1210 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1211 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1212 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1213 66d1f035 René Nussbaumer
1214 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1215 66d1f035 René Nussbaumer
1216 66d1f035 René Nussbaumer
1217 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1218 66d1f035 René Nussbaumer
  """Does the actual power off.
1219 66d1f035 René Nussbaumer

1220 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1221 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1222 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1223 66d1f035 René Nussbaumer
  @return: The desired exit status
1224 66d1f035 René Nussbaumer

1225 66d1f035 René Nussbaumer
  """
1226 66d1f035 René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False):
1227 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1228 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1229 66d1f035 René Nussbaumer
1230 66d1f035 René Nussbaumer
  if not node_list:
1231 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1232 66d1f035 René Nussbaumer
1233 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1234 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1235 66d1f035 René Nussbaumer
  else:
1236 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1237 66d1f035 René Nussbaumer
1238 66d1f035 René Nussbaumer
1239 66d1f035 René Nussbaumer
def Epo(opts, args):
1240 66d1f035 René Nussbaumer
  """EPO operations.
1241 66d1f035 René Nussbaumer

1242 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1243 66d1f035 René Nussbaumer
  @type args: list
1244 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1245 66d1f035 René Nussbaumer
  @rtype: int
1246 66d1f035 René Nussbaumer
  @return: the desired exit code
1247 66d1f035 René Nussbaumer

1248 66d1f035 René Nussbaumer
  """
1249 66d1f035 René Nussbaumer
  if opts.groups and opts.show_all:
1250 66d1f035 René Nussbaumer
    ToStderr("Only one of --groups or --all are allowed")
1251 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1252 66d1f035 René Nussbaumer
  elif args and opts.show_all:
1253 66d1f035 René Nussbaumer
    ToStderr("Arguments in combination with --all are not allowed")
1254 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1255 66d1f035 René Nussbaumer
1256 66d1f035 René Nussbaumer
  client = GetClient()
1257 66d1f035 René Nussbaumer
1258 66d1f035 René Nussbaumer
  if opts.groups:
1259 66d1f035 René Nussbaumer
    node_query_list = itertools.chain(*client.QueryGroups(names=args,
1260 66d1f035 René Nussbaumer
                                                          fields=["node_list"],
1261 66d1f035 René Nussbaumer
                                                          use_locking=False))
1262 66d1f035 René Nussbaumer
  else:
1263 66d1f035 René Nussbaumer
    node_query_list = args
1264 66d1f035 René Nussbaumer
1265 66d1f035 René Nussbaumer
  result = client.QueryNodes(names=node_query_list,
1266 66d1f035 René Nussbaumer
                             fields=["name", "master", "pinst_list",
1267 66d1f035 René Nussbaumer
                                     "sinst_list", "powered", "offline"],
1268 66d1f035 René Nussbaumer
                             use_locking=False)
1269 66d1f035 René Nussbaumer
  node_list = []
1270 66d1f035 René Nussbaumer
  inst_map = {}
1271 66d1f035 René Nussbaumer
  for (idx, (node, master, pinsts, sinsts, powered,
1272 66d1f035 René Nussbaumer
             offline)) in enumerate(result):
1273 66d1f035 René Nussbaumer
    # Normalize the node_query_list as well
1274 66d1f035 René Nussbaumer
    if not opts.show_all:
1275 66d1f035 René Nussbaumer
      node_query_list[idx] = node
1276 66d1f035 René Nussbaumer
    if not offline:
1277 66d1f035 René Nussbaumer
      for inst in (pinsts + sinsts):
1278 66d1f035 René Nussbaumer
        if inst in inst_map:
1279 66d1f035 René Nussbaumer
          if not master:
1280 66d1f035 René Nussbaumer
            inst_map[inst].add(node)
1281 66d1f035 René Nussbaumer
        elif master:
1282 66d1f035 René Nussbaumer
          inst_map[inst] = set()
1283 66d1f035 René Nussbaumer
        else:
1284 66d1f035 René Nussbaumer
          inst_map[inst] = set([node])
1285 66d1f035 René Nussbaumer
1286 66d1f035 René Nussbaumer
    if master and opts.on:
1287 66d1f035 René Nussbaumer
      # We ignore the master for turning on the machines, in fact we are
1288 66d1f035 René Nussbaumer
      # already operating on the master at this point :)
1289 66d1f035 René Nussbaumer
      continue
1290 66d1f035 René Nussbaumer
    elif master and not opts.show_all:
1291 66d1f035 René Nussbaumer
      ToStderr("%s is the master node, please do a master-failover to another"
1292 66d1f035 René Nussbaumer
               " node not affected by the EPO or use --all if you intend to"
1293 66d1f035 René Nussbaumer
               " shutdown the whole cluster", node)
1294 66d1f035 René Nussbaumer
      return constants.EXIT_FAILURE
1295 66d1f035 René Nussbaumer
    elif powered is None:
1296 66d1f035 René Nussbaumer
      ToStdout("Node %s does not support out-of-band handling, it can not be"
1297 66d1f035 René Nussbaumer
               " handled in a fully automated manner", node)
1298 66d1f035 René Nussbaumer
    elif powered == opts.on:
1299 66d1f035 René Nussbaumer
      ToStdout("Node %s is already in desired power state, skipping", node)
1300 66d1f035 René Nussbaumer
    elif not offline or (offline and powered):
1301 66d1f035 René Nussbaumer
      node_list.append(node)
1302 66d1f035 René Nussbaumer
1303 66d1f035 René Nussbaumer
  if not opts.force and not ConfirmOperation(node_query_list, "nodes", "epo"):
1304 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1305 66d1f035 René Nussbaumer
1306 66d1f035 René Nussbaumer
  if opts.on:
1307 66d1f035 René Nussbaumer
    return _EpoOn(opts, node_query_list, node_list, inst_map)
1308 66d1f035 René Nussbaumer
  else:
1309 66d1f035 René Nussbaumer
    return _EpoOff(opts, node_list, inst_map)
1310 66d1f035 René Nussbaumer
1311 66d1f035 René Nussbaumer
1312 a8083063 Iustin Pop
commands = {
1313 d0c8c01d Iustin Pop
  "init": (
1314 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
1315 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
1316 6ea815cf Iustin Pop
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
1317 b989b9d9 Ken Wehr
     NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
1318 39b0f0c2 Balazs Lecz
     SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
1319 bf4af505 Apollon Oikonomopoulos
     UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
1320 6204ee71 René Nussbaumer
     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
1321 7925d409 Apollon Oikonomopoulos
     NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT],
1322 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
1323 d0c8c01d Iustin Pop
  "destroy": (
1324 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
1325 6ea815cf Iustin Pop
    "", "Destroy cluster"),
1326 d0c8c01d Iustin Pop
  "rename": (
1327 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
1328 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
1329 6ea815cf Iustin Pop
    "<new_name>",
1330 6ea815cf Iustin Pop
    "Renames the cluster"),
1331 d0c8c01d Iustin Pop
  "redist-conf": (
1332 aa06f8c6 Michael Hanselmann
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1333 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
1334 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
1335 d0c8c01d Iustin Pop
  "verify": (
1336 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
1337 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
1338 40167d65 Adeodato Simo
     DRY_RUN_OPT, PRIORITY_OPT, NODEGROUP_OPT],
1339 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
1340 d0c8c01d Iustin Pop
  "verify-disks": (
1341 aa06f8c6 Michael Hanselmann
    VerifyDisks, ARGS_NONE, [PRIORITY_OPT],
1342 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
1343 d0c8c01d Iustin Pop
  "repair-disk-sizes": (
1344 aa06f8c6 Michael Hanselmann
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
1345 6ea815cf Iustin Pop
    "", "Updates mismatches in recorded disk sizes"),
1346 d0c8c01d Iustin Pop
  "master-failover": (
1347 064c21f8 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT],
1348 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
1349 d0c8c01d Iustin Pop
  "master-ping": (
1350 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
1351 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
1352 d0c8c01d Iustin Pop
  "version": (
1353 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
1354 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
1355 d0c8c01d Iustin Pop
  "getmaster": (
1356 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
1357 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
1358 d0c8c01d Iustin Pop
  "copyfile": (
1359 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
1360 b6e88032 Michael Hanselmann
    [NODE_LIST_OPT, USE_REPL_NET_OPT, NODEGROUP_OPT],
1361 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
1362 d0c8c01d Iustin Pop
  "command": (
1363 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
1364 b6e88032 Michael Hanselmann
    [NODE_LIST_OPT, NODEGROUP_OPT],
1365 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
1366 d0c8c01d Iustin Pop
  "info": (
1367 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
1368 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
1369 d0c8c01d Iustin Pop
  "list-tags": (
1370 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
1371 d0c8c01d Iustin Pop
  "add-tags": (
1372 aa06f8c6 Michael Hanselmann
    AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
1373 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
1374 d0c8c01d Iustin Pop
  "remove-tags": (
1375 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
1376 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
1377 d0c8c01d Iustin Pop
  "search-tags": (
1378 aa06f8c6 Michael Hanselmann
    SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "",
1379 aa06f8c6 Michael Hanselmann
    "Searches the tags on all objects on"
1380 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
1381 d0c8c01d Iustin Pop
  "queue": (
1382 6ea815cf Iustin Pop
    QueueOps,
1383 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
1384 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
1385 d0c8c01d Iustin Pop
  "watcher": (
1386 6ea815cf Iustin Pop
    WatcherOps,
1387 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
1388 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
1389 064c21f8 Iustin Pop
    [],
1390 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
1391 d0c8c01d Iustin Pop
  "modify": (
1392 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
1393 38f9d2cf Guido Trotter
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
1394 1338f2b4 Balazs Lecz
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
1395 ed14ed48 Luca Bigliardi
     UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT,
1396 db5a8a2d Iustin Pop
     NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, RESERVED_LVS_OPT,
1397 6204ee71 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT, NODE_PARAMS_OPT],
1398 6ea815cf Iustin Pop
    "[opts...]",
1399 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
1400 6d4a1656 Michael Hanselmann
  "renew-crypto": (
1401 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
1402 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
1403 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
1404 b6267745 Andrea Spadaccini
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT,
1405 b6267745 Andrea Spadaccini
     NEW_SPICE_CERT_OPT, SPICE_CERT_OPT, SPICE_CACERT_OPT],
1406 6d4a1656 Michael Hanselmann
    "[opts...]",
1407 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
1408 66d1f035 René Nussbaumer
  "epo": (
1409 66d1f035 René Nussbaumer
    Epo, [ArgUnknown()],
1410 fcecea0b René Nussbaumer
    [FORCE_OPT, ON_OPT, GROUPS_OPT, ALL_OPT, OOB_TIMEOUT_OPT,
1411 cfed3b9f René Nussbaumer
     SHUTDOWN_TIMEOUT_OPT, POWER_DELAY_OPT],
1412 66d1f035 René Nussbaumer
    "[opts...] [args]",
1413 66d1f035 René Nussbaumer
    "Performs an emergency power-off on given args"),
1414 a8083063 Iustin Pop
  }
1415 a8083063 Iustin Pop
1416 6d4a1656 Michael Hanselmann
1417 c28502b1 Iustin Pop
#: dictionary with aliases for commands
1418 c28502b1 Iustin Pop
aliases = {
1419 d0c8c01d Iustin Pop
  "masterfailover": "master-failover",
1420 c28502b1 Iustin Pop
}
1421 c28502b1 Iustin Pop
1422 c28502b1 Iustin Pop
1423 7b3e7d41 Michael Hanselmann
def Main():
1424 7b3e7d41 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
1425 7b3e7d41 Michael Hanselmann
                     aliases=aliases)