Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 080fbeea

History | View | Annotate | Download (44.2 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 fb44c6db Andrea Spadaccini
def ActivateMasterIp(opts, args):
227 fb44c6db Andrea Spadaccini
  """Activates the master IP.
228 fb44c6db Andrea Spadaccini

229 fb44c6db Andrea Spadaccini
  """
230 fb44c6db Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
231 fb44c6db Andrea Spadaccini
  SubmitOpCode(op)
232 fb44c6db Andrea Spadaccini
  return 0
233 fb44c6db Andrea Spadaccini
234 fb44c6db Andrea Spadaccini
235 fb44c6db Andrea Spadaccini
def DeactivateMasterIp(opts, args):
236 fb44c6db Andrea Spadaccini
  """Deactivates the master IP.
237 fb44c6db Andrea Spadaccini

238 fb44c6db Andrea Spadaccini
  """
239 fb44c6db Andrea Spadaccini
  if not opts.confirm:
240 fb44c6db Andrea Spadaccini
    usertext = ("This will disable the master IP. All the open connections to"
241 fb44c6db Andrea Spadaccini
                " the master IP will be closed. To reach the master you will"
242 fb44c6db Andrea Spadaccini
                " need to use its node IP."
243 fb44c6db Andrea Spadaccini
                " Continue?")
244 fb44c6db Andrea Spadaccini
    if not AskUser(usertext):
245 fb44c6db Andrea Spadaccini
      return 1
246 fb44c6db Andrea Spadaccini
247 fb44c6db Andrea Spadaccini
  op = opcodes.OpClusterDeactivateMasterIp()
248 fb44c6db Andrea Spadaccini
  SubmitOpCode(op)
249 fb44c6db Andrea Spadaccini
  return 0
250 fb44c6db Andrea Spadaccini
251 fb44c6db Andrea Spadaccini
252 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
253 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
254 afee0879 Iustin Pop

255 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
256 afee0879 Iustin Pop
  @type args: list
257 afee0879 Iustin Pop
  @param args: empty list
258 afee0879 Iustin Pop
  @rtype: int
259 afee0879 Iustin Pop
  @return: the desired exit code
260 afee0879 Iustin Pop

261 afee0879 Iustin Pop
  """
262 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
263 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
264 afee0879 Iustin Pop
  return 0
265 afee0879 Iustin Pop
266 afee0879 Iustin Pop
267 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
268 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
269 a8083063 Iustin Pop

270 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
271 469ee405 Iustin Pop
  @type args: list
272 469ee405 Iustin Pop
  @param args: should be an empty list
273 469ee405 Iustin Pop
  @rtype: int
274 469ee405 Iustin Pop
  @return: the desired exit code
275 a8083063 Iustin Pop

276 a8083063 Iustin Pop
  """
277 2e7b8369 Iustin Pop
  cl = GetClient()
278 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
279 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
280 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
281 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
282 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
283 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
284 a8083063 Iustin Pop
  return 0
285 a8083063 Iustin Pop
286 a8083063 Iustin Pop
287 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
288 a8083063 Iustin Pop
  """Write name of master node to the standard output.
289 a8083063 Iustin Pop

290 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
291 469ee405 Iustin Pop
  @type args: list
292 469ee405 Iustin Pop
  @param args: should be an empty list
293 469ee405 Iustin Pop
  @rtype: int
294 469ee405 Iustin Pop
  @return: the desired exit code
295 a8083063 Iustin Pop

296 a8083063 Iustin Pop
  """
297 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
298 8eb148ae Iustin Pop
  ToStdout(master)
299 a8083063 Iustin Pop
  return 0
300 a8083063 Iustin Pop
301 cac599f1 Michael Hanselmann
302 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
303 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
304 1094acda Guido Trotter

305 1094acda Guido Trotter
  @type paramsdict: dict of dicts
306 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
307 664a9d73 René Nussbaumer
  @type level: int
308 664a9d73 René Nussbaumer
  @param level: Level of indention
309 1094acda Guido Trotter

310 1094acda Guido Trotter
  """
311 664a9d73 René Nussbaumer
  indent = "  " * level
312 9d91c6ab Guido Trotter
  for item, val in sorted(paramsdict.items()):
313 664a9d73 René Nussbaumer
    if isinstance(val, dict):
314 664a9d73 René Nussbaumer
      ToStdout("%s- %s:", indent, item)
315 d729e03a Guido Trotter
      _PrintGroupedParams(val, level=level + 1, roman=roman)
316 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
317 d729e03a Guido Trotter
      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
318 664a9d73 René Nussbaumer
    else:
319 664a9d73 René Nussbaumer
      ToStdout("%s  %s: %s", indent, item, val)
320 a8083063 Iustin Pop
321 cac599f1 Michael Hanselmann
322 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
323 a8083063 Iustin Pop
  """Shows cluster information.
324 a8083063 Iustin Pop

325 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
326 469ee405 Iustin Pop
  @type args: list
327 469ee405 Iustin Pop
  @param args: should be an empty list
328 469ee405 Iustin Pop
  @rtype: int
329 469ee405 Iustin Pop
  @return: the desired exit code
330 469ee405 Iustin Pop

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

409 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
410 469ee405 Iustin Pop
  @type args: list
411 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
412 469ee405 Iustin Pop
      the file to be copied
413 469ee405 Iustin Pop
  @rtype: int
414 469ee405 Iustin Pop
  @return: the desired exit code
415 a8083063 Iustin Pop

416 a8083063 Iustin Pop
  """
417 b3989551 Iustin Pop
  filename = args[0]
418 b3989551 Iustin Pop
  if not os.path.exists(filename):
419 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
420 debac808 Iustin Pop
                               errors.ECODE_INVAL)
421 b3989551 Iustin Pop
422 56bece1f Iustin Pop
  cl = GetClient()
423 56bece1f Iustin Pop
424 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
425 56bece1f Iustin Pop
426 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
427 b6e88032 Michael Hanselmann
                           secondary_ips=opts.use_replication_network,
428 b6e88032 Michael Hanselmann
                           nodegroup=opts.nodegroup)
429 e00ea635 Michael Hanselmann
430 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
431 b3989551 Iustin Pop
  for node in results:
432 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
433 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
434 b3989551 Iustin Pop
435 a8083063 Iustin Pop
  return 0
436 a8083063 Iustin Pop
437 a8083063 Iustin Pop
438 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
439 a8083063 Iustin Pop
  """Run a command on some nodes.
440 a8083063 Iustin Pop

441 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
442 469ee405 Iustin Pop
  @type args: list
443 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
444 469ee405 Iustin Pop
  @rtype: int
445 469ee405 Iustin Pop
  @return: the desired exit code
446 a8083063 Iustin Pop

447 a8083063 Iustin Pop
  """
448 56bece1f Iustin Pop
  cl = GetClient()
449 7688d0d3 Michael Hanselmann
450 a8083063 Iustin Pop
  command = " ".join(args)
451 4040a784 Iustin Pop
452 b6e88032 Michael Hanselmann
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl, nodegroup=opts.nodegroup)
453 56bece1f Iustin Pop
454 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
455 56bece1f Iustin Pop
                                                    "master_node"])
456 b3989551 Iustin Pop
457 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
458 b3989551 Iustin Pop
459 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
460 b3989551 Iustin Pop
  if master_node in nodes:
461 b3989551 Iustin Pop
    nodes.remove(master_node)
462 b3989551 Iustin Pop
    nodes.append(master_node)
463 b3989551 Iustin Pop
464 b3989551 Iustin Pop
  for name in nodes:
465 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
466 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
467 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
468 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
469 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
470 b3989551 Iustin Pop
471 b3989551 Iustin Pop
  return 0
472 a8083063 Iustin Pop
473 a8083063 Iustin Pop
474 a8083063 Iustin Pop
def VerifyCluster(opts, args):
475 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
476 a8083063 Iustin Pop

477 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
478 469ee405 Iustin Pop
  @type args: list
479 469ee405 Iustin Pop
  @param args: should be an empty list
480 469ee405 Iustin Pop
  @rtype: int
481 469ee405 Iustin Pop
  @return: the desired exit code
482 a8083063 Iustin Pop

483 a8083063 Iustin Pop
  """
484 8d59409f Iustin Pop
  skip_checks = []
485 bf93ae69 Adeodato Simo
486 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
487 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
488 bf93ae69 Adeodato Simo
489 fcad7225 Michael Hanselmann
  cl = GetClient()
490 bf93ae69 Adeodato Simo
491 fcad7225 Michael Hanselmann
  op = opcodes.OpClusterVerify(verbose=opts.verbose,
492 fcad7225 Michael Hanselmann
                               error_codes=opts.error_codes,
493 fcad7225 Michael Hanselmann
                               debug_simulate_errors=opts.simulate_errors,
494 fcad7225 Michael Hanselmann
                               skip_checks=skip_checks,
495 fcad7225 Michael Hanselmann
                               group_name=opts.nodegroup)
496 fcad7225 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
497 bf93ae69 Adeodato Simo
498 fcad7225 Michael Hanselmann
  # Keep track of submitted jobs
499 fcad7225 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
500 fcad7225 Michael Hanselmann
501 fcad7225 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
502 fcad7225 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
503 bf93ae69 Adeodato Simo
504 fcad7225 Michael Hanselmann
  results = jex.GetResults()
505 ebe6cf38 Michael Hanselmann
506 ebe6cf38 Michael Hanselmann
  (bad_jobs, bad_results) = \
507 ebe6cf38 Michael Hanselmann
    map(len,
508 ebe6cf38 Michael Hanselmann
        # Convert iterators to lists
509 ebe6cf38 Michael Hanselmann
        map(list,
510 ebe6cf38 Michael Hanselmann
            # Count errors
511 ebe6cf38 Michael Hanselmann
            map(compat.partial(itertools.ifilterfalse, bool),
512 ebe6cf38 Michael Hanselmann
                # Convert result to booleans in a tuple
513 ebe6cf38 Michael Hanselmann
                zip(*((job_success, len(op_results) == 1 and op_results[0])
514 ebe6cf38 Michael Hanselmann
                      for (job_success, op_results) in results)))))
515 ebe6cf38 Michael Hanselmann
516 ebe6cf38 Michael Hanselmann
  if bad_jobs == 0 and bad_results == 0:
517 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
518 e0508c86 Guido Trotter
  else:
519 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
520 ebe6cf38 Michael Hanselmann
    if bad_jobs > 0:
521 ebe6cf38 Michael Hanselmann
      ToStdout("%s job(s) failed while verifying the cluster.", bad_jobs)
522 fcad7225 Michael Hanselmann
523 fcad7225 Michael Hanselmann
  return rcode
524 a8083063 Iustin Pop
525 a8083063 Iustin Pop
526 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
527 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
528 f4d4e184 Iustin Pop

529 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
530 469ee405 Iustin Pop
  @type args: list
531 469ee405 Iustin Pop
  @param args: should be an empty list
532 469ee405 Iustin Pop
  @rtype: int
533 469ee405 Iustin Pop
  @return: the desired exit code
534 f4d4e184 Iustin Pop

535 f4d4e184 Iustin Pop
  """
536 f1b083ce Michael Hanselmann
  cl = GetClient()
537 f1b083ce Michael Hanselmann
538 bd8210a7 Iustin Pop
  op = opcodes.OpClusterVerifyDisks()
539 f4d4e184 Iustin Pop
540 ae1a845c Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
541 ae1a845c Michael Hanselmann
542 ae1a845c Michael Hanselmann
  # Keep track of submitted jobs
543 ae1a845c Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
544 ae1a845c Michael Hanselmann
545 ae1a845c Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
546 ae1a845c Michael Hanselmann
    jex.AddJobId(None, status, job_id)
547 b63ed789 Iustin Pop
548 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
549 b63ed789 Iustin Pop
550 ae1a845c Michael Hanselmann
  for (status, result) in jex.GetResults():
551 ae1a845c Michael Hanselmann
    if not status:
552 ae1a845c Michael Hanselmann
      ToStdout("Job failed: %s", result)
553 ae1a845c Michael Hanselmann
      continue
554 ae1a845c Michael Hanselmann
555 ae1a845c Michael Hanselmann
    ((bad_nodes, instances, missing), ) = result
556 ae1a845c Michael Hanselmann
557 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
558 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
559 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
560 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
561 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
562 b63ed789 Iustin Pop
563 f4d4e184 Iustin Pop
    for iname in instances:
564 b63ed789 Iustin Pop
      if iname in missing:
565 b63ed789 Iustin Pop
        continue
566 83f5d475 Iustin Pop
      op = opcodes.OpInstanceActivateDisks(instance_name=iname)
567 f4d4e184 Iustin Pop
      try:
568 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
569 f1b083ce Michael Hanselmann
        SubmitOpCode(op, opts=opts, cl=cl)
570 f4d4e184 Iustin Pop
      except errors.GenericError, err:
571 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
572 f4d4e184 Iustin Pop
        retcode |= nret
573 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
574 b63ed789 Iustin Pop
575 ae1a845c Michael Hanselmann
    if missing:
576 ae1a845c Michael Hanselmann
      for iname, ival in missing.iteritems():
577 ae1a845c Michael Hanselmann
        all_missing = compat.all(x[0] in bad_nodes for x in ival)
578 ae1a845c Michael Hanselmann
        if all_missing:
579 ae1a845c Michael Hanselmann
          ToStdout("Instance %s cannot be verified as it lives on"
580 ae1a845c Michael Hanselmann
                   " broken nodes", iname)
581 ae1a845c Michael Hanselmann
        else:
582 ae1a845c Michael Hanselmann
          ToStdout("Instance %s has missing logical volumes:", iname)
583 ae1a845c Michael Hanselmann
          ival.sort()
584 ae1a845c Michael Hanselmann
          for node, vol in ival:
585 ae1a845c Michael Hanselmann
            if node in bad_nodes:
586 ae1a845c Michael Hanselmann
              ToStdout("\tbroken node %s /dev/%s", node, vol)
587 ae1a845c Michael Hanselmann
            else:
588 ae1a845c Michael Hanselmann
              ToStdout("\t%s /dev/%s", node, vol)
589 ae1a845c Michael Hanselmann
590 ae1a845c Michael Hanselmann
      ToStdout("You need to replace or recreate disks for all the above"
591 ae1a845c Michael Hanselmann
               " instances if this message persists after fixing broken nodes.")
592 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
593 f4d4e184 Iustin Pop
594 f4d4e184 Iustin Pop
  return retcode
595 f4d4e184 Iustin Pop
596 f4d4e184 Iustin Pop
597 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
598 60975797 Iustin Pop
  """Verify sizes of cluster disks.
599 60975797 Iustin Pop

600 60975797 Iustin Pop
  @param opts: the command line options selected by the user
601 60975797 Iustin Pop
  @type args: list
602 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
603 60975797 Iustin Pop
  @rtype: int
604 60975797 Iustin Pop
  @return: the desired exit code
605 60975797 Iustin Pop

606 60975797 Iustin Pop
  """
607 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
608 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
609 60975797 Iustin Pop
610 60975797 Iustin Pop
611 4331f6cd Michael Hanselmann
@UsesRPC
612 a8083063 Iustin Pop
def MasterFailover(opts, args):
613 a8083063 Iustin Pop
  """Failover the master node.
614 a8083063 Iustin Pop

615 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
616 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
617 a8083063 Iustin Pop
  master.
618 a8083063 Iustin Pop

619 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
620 469ee405 Iustin Pop
  @type args: list
621 469ee405 Iustin Pop
  @param args: should be an empty list
622 469ee405 Iustin Pop
  @rtype: int
623 469ee405 Iustin Pop
  @return: the desired exit code
624 469ee405 Iustin Pop

625 a8083063 Iustin Pop
  """
626 8e2524c3 Guido Trotter
  if opts.no_voting:
627 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
628 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
629 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
630 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
631 8e2524c3 Guido Trotter
    if not AskUser(usertext):
632 8e2524c3 Guido Trotter
      return 1
633 8e2524c3 Guido Trotter
634 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
635 a8083063 Iustin Pop
636 a8083063 Iustin Pop
637 4404ffad Iustin Pop
def MasterPing(opts, args):
638 4404ffad Iustin Pop
  """Checks if the master is alive.
639 4404ffad Iustin Pop

640 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
641 4404ffad Iustin Pop
  @type args: list
642 4404ffad Iustin Pop
  @param args: should be an empty list
643 4404ffad Iustin Pop
  @rtype: int
644 4404ffad Iustin Pop
  @return: the desired exit code
645 4404ffad Iustin Pop

646 4404ffad Iustin Pop
  """
647 4404ffad Iustin Pop
  try:
648 4404ffad Iustin Pop
    cl = GetClient()
649 4404ffad Iustin Pop
    cl.QueryClusterInfo()
650 4404ffad Iustin Pop
    return 0
651 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
652 4404ffad Iustin Pop
    return 1
653 4404ffad Iustin Pop
654 4404ffad Iustin Pop
655 73415719 Iustin Pop
def SearchTags(opts, args):
656 73415719 Iustin Pop
  """Searches the tags on all the cluster.
657 73415719 Iustin Pop

658 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
659 469ee405 Iustin Pop
  @type args: list
660 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
661 469ee405 Iustin Pop
  @rtype: int
662 469ee405 Iustin Pop
  @return: the desired exit code
663 469ee405 Iustin Pop

664 73415719 Iustin Pop
  """
665 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
666 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
667 73415719 Iustin Pop
  if not result:
668 73415719 Iustin Pop
    return 1
669 73415719 Iustin Pop
  result = list(result)
670 73415719 Iustin Pop
  result.sort()
671 73415719 Iustin Pop
  for path, tag in result:
672 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
673 73415719 Iustin Pop
674 73415719 Iustin Pop
675 0aee8ee9 Guido Trotter
def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
676 0aee8ee9 Guido Trotter
                 new_confd_hmac_key, new_cds, cds_filename,
677 0aee8ee9 Guido Trotter
                 force):
678 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
679 6d4a1656 Michael Hanselmann

680 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
681 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
682 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
683 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
684 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
685 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
686 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
687 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
688 3db3eb2a Michael Hanselmann
  @type new_cds: bool
689 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
690 3db3eb2a Michael Hanselmann
  @type cds_filename: string
691 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
692 6d4a1656 Michael Hanselmann
  @type force: bool
693 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
694 6d4a1656 Michael Hanselmann

695 6d4a1656 Michael Hanselmann
  """
696 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
697 6e060e15 Andrea Spadaccini
    ToStderr("Only one of the --new-rapi-certificate and --rapi-certificate"
698 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
699 6d4a1656 Michael Hanselmann
    return 1
700 6d4a1656 Michael Hanselmann
701 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
702 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
703 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
704 3db3eb2a Michael Hanselmann
             " the same time.")
705 3db3eb2a Michael Hanselmann
    return 1
706 3db3eb2a Michael Hanselmann
707 0aee8ee9 Guido Trotter
  if rapi_cert_filename:
708 0aee8ee9 Guido Trotter
    # Read and verify new certificate
709 0aee8ee9 Guido Trotter
    try:
710 0aee8ee9 Guido Trotter
      rapi_cert_pem = utils.ReadFile(rapi_cert_filename)
711 6d4a1656 Michael Hanselmann
712 0aee8ee9 Guido Trotter
      OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
713 0aee8ee9 Guido Trotter
                                      rapi_cert_pem)
714 0aee8ee9 Guido Trotter
    except Exception, err: # pylint: disable=W0703
715 0aee8ee9 Guido Trotter
      ToStderr("Can't load new RAPI certificate from %s: %s" %
716 0aee8ee9 Guido Trotter
               (rapi_cert_filename, str(err)))
717 0aee8ee9 Guido Trotter
      return 1
718 6d4a1656 Michael Hanselmann
719 0aee8ee9 Guido Trotter
    try:
720 0aee8ee9 Guido Trotter
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, rapi_cert_pem)
721 0aee8ee9 Guido Trotter
    except Exception, err: # pylint: disable=W0703
722 0aee8ee9 Guido Trotter
      ToStderr("Can't load new RAPI private key from %s: %s" %
723 0aee8ee9 Guido Trotter
               (rapi_cert_filename, str(err)))
724 0aee8ee9 Guido Trotter
      return 1
725 0aee8ee9 Guido Trotter
726 0aee8ee9 Guido Trotter
  else:
727 0aee8ee9 Guido Trotter
    rapi_cert_pem = None
728 6d4a1656 Michael Hanselmann
729 3db3eb2a Michael Hanselmann
  if cds_filename:
730 3db3eb2a Michael Hanselmann
    try:
731 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
732 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
733 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
734 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
735 3db3eb2a Michael Hanselmann
      return 1
736 3db3eb2a Michael Hanselmann
  else:
737 3db3eb2a Michael Hanselmann
    cds = None
738 3db3eb2a Michael Hanselmann
739 6d4a1656 Michael Hanselmann
  if not force:
740 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
741 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
742 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
743 6d4a1656 Michael Hanselmann
      return 1
744 6d4a1656 Michael Hanselmann
745 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
746 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
747 0aee8ee9 Guido Trotter
    bootstrap.GenerateClusterCrypto(new_cluster_cert, new_rapi_cert,
748 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
749 3db3eb2a Michael Hanselmann
                                    new_cds,
750 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
751 3db3eb2a Michael Hanselmann
                                    cds=cds)
752 6d4a1656 Michael Hanselmann
753 6d4a1656 Michael Hanselmann
    files_to_copy = []
754 6d4a1656 Michael Hanselmann
755 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
756 168c1de2 Michael Hanselmann
      files_to_copy.append(constants.NODED_CERT_FILE)
757 6d4a1656 Michael Hanselmann
758 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
759 6d4a1656 Michael Hanselmann
      files_to_copy.append(constants.RAPI_CERT_FILE)
760 6d4a1656 Michael Hanselmann
761 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
762 6b7d5878 Michael Hanselmann
      files_to_copy.append(constants.CONFD_HMAC_KEY)
763 6d4a1656 Michael Hanselmann
764 3db3eb2a Michael Hanselmann
    if new_cds or cds:
765 3db3eb2a Michael Hanselmann
      files_to_copy.append(constants.CLUSTER_DOMAIN_SECRET_FILE)
766 3db3eb2a Michael Hanselmann
767 6d4a1656 Michael Hanselmann
    if files_to_copy:
768 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
769 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
770 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
771 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
772 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
773 6d4a1656 Michael Hanselmann
774 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
775 6d4a1656 Michael Hanselmann
776 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
777 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
778 6d4a1656 Michael Hanselmann
779 6d4a1656 Michael Hanselmann
  return 0
780 6d4a1656 Michael Hanselmann
781 6d4a1656 Michael Hanselmann
782 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
783 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
784 6d4a1656 Michael Hanselmann

785 6d4a1656 Michael Hanselmann
  """
786 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
787 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
788 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
789 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
790 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
791 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
792 6d4a1656 Michael Hanselmann
                      opts.force)
793 6d4a1656 Michael Hanselmann
794 6d4a1656 Michael Hanselmann
795 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
796 90b6aa3a Manuel Franceschini
  """Modify the cluster.
797 90b6aa3a Manuel Franceschini

798 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
799 469ee405 Iustin Pop
  @type args: list
800 469ee405 Iustin Pop
  @param args: should be an empty list
801 469ee405 Iustin Pop
  @rtype: int
802 469ee405 Iustin Pop
  @return: the desired exit code
803 90b6aa3a Manuel Franceschini

804 90b6aa3a Manuel Franceschini
  """
805 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
806 ed14ed48 Luca Bigliardi
          not opts.drbd_storage or opts.drbd_helper or
807 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
808 6204ee71 René Nussbaumer
          opts.beparams or opts.nicparams or opts.ndparams or
809 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
810 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
811 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
812 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
813 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
814 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
815 b883637f René Nussbaumer
          opts.reserved_lvs is not None or
816 38f9d2cf Guido Trotter
          opts.master_netdev is not None or
817 b883637f René Nussbaumer
          opts.prealloc_wipe_disks is not None):
818 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
819 90b6aa3a Manuel Franceschini
    return 1
820 90b6aa3a Manuel Franceschini
821 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
822 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
823 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
824 90b6aa3a Manuel Franceschini
    return 1
825 6d4a1656 Michael Hanselmann
826 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
827 6d4a1656 Michael Hanselmann
    vg_name = ""
828 90b6aa3a Manuel Franceschini
829 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
830 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
831 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
832 ed14ed48 Luca Bigliardi
    return 1
833 ed14ed48 Luca Bigliardi
834 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage:
835 ed14ed48 Luca Bigliardi
    drbd_helper = ""
836 ed14ed48 Luca Bigliardi
837 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
838 779c15bb Iustin Pop
  if hvlist is not None:
839 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
840 779c15bb Iustin Pop
841 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
842 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
843 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
844 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
845 779c15bb Iustin Pop
846 779c15bb Iustin Pop
  beparams = opts.beparams
847 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
848 779c15bb Iustin Pop
849 5af3da74 Guido Trotter
  nicparams = opts.nicparams
850 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
851 5af3da74 Guido Trotter
852 6204ee71 René Nussbaumer
  ndparams = opts.ndparams
853 6204ee71 René Nussbaumer
  if ndparams is not None:
854 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
855 1338f2b4 Balazs Lecz
856 3953242f Iustin Pop
  mnh = opts.maintain_node_health
857 3953242f Iustin Pop
858 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
859 1338f2b4 Balazs Lecz
  if uid_pool is not None:
860 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
861 1338f2b4 Balazs Lecz
862 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
863 fdad8c4d Balazs Lecz
  if add_uids is not None:
864 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
865 fdad8c4d Balazs Lecz
866 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
867 fdad8c4d Balazs Lecz
  if remove_uids is not None:
868 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
869 fdad8c4d Balazs Lecz
870 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
871 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
872 f38ea602 Iustin Pop
      opts.reserved_lvs = []
873 f38ea602 Iustin Pop
    else:
874 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
875 f38ea602 Iustin Pop
876 a6682fdc Iustin Pop
  op = opcodes.OpClusterSetParams(vg_name=vg_name,
877 ed14ed48 Luca Bigliardi
                                  drbd_helper=drbd_helper,
878 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
879 779c15bb Iustin Pop
                                  hvparams=hvparams,
880 17463d22 René Nussbaumer
                                  os_hvp=None,
881 4b7735f9 Iustin Pop
                                  beparams=beparams,
882 5af3da74 Guido Trotter
                                  nicparams=nicparams,
883 6204ee71 René Nussbaumer
                                  ndparams=ndparams,
884 3953242f Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size,
885 1338f2b4 Balazs Lecz
                                  maintain_node_health=mnh,
886 fdad8c4d Balazs Lecz
                                  uid_pool=uid_pool,
887 fdad8c4d Balazs Lecz
                                  add_uids=add_uids,
888 bf4af505 Apollon Oikonomopoulos
                                  remove_uids=remove_uids,
889 f38ea602 Iustin Pop
                                  default_iallocator=opts.default_iallocator,
890 b883637f René Nussbaumer
                                  prealloc_wipe_disks=opts.prealloc_wipe_disks,
891 38f9d2cf Guido Trotter
                                  master_netdev=opts.master_netdev,
892 f38ea602 Iustin Pop
                                  reserved_lvs=opts.reserved_lvs)
893 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
894 90b6aa3a Manuel Franceschini
  return 0
895 90b6aa3a Manuel Franceschini
896 90b6aa3a Manuel Franceschini
897 3ccafd0e Iustin Pop
def QueueOps(opts, args):
898 3ccafd0e Iustin Pop
  """Queue operations.
899 3ccafd0e Iustin Pop

900 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
901 469ee405 Iustin Pop
  @type args: list
902 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
903 469ee405 Iustin Pop
  @rtype: int
904 469ee405 Iustin Pop
  @return: the desired exit code
905 469ee405 Iustin Pop

906 3ccafd0e Iustin Pop
  """
907 3ccafd0e Iustin Pop
  command = args[0]
908 3ccafd0e Iustin Pop
  client = GetClient()
909 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
910 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
911 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
912 3ccafd0e Iustin Pop
  elif command == "info":
913 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
914 3ccafd0e Iustin Pop
    if result[0]:
915 3a24c527 Iustin Pop
      val = "set"
916 3ccafd0e Iustin Pop
    else:
917 3a24c527 Iustin Pop
      val = "unset"
918 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
919 2e668b38 Guido Trotter
  else:
920 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
921 debac808 Iustin Pop
                               errors.ECODE_INVAL)
922 2e668b38 Guido Trotter
923 3ccafd0e Iustin Pop
  return 0
924 3ccafd0e Iustin Pop
925 95b2e626 Michael Hanselmann
926 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
927 28b498cd Michael Hanselmann
  if until is None or until < time.time():
928 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
929 28b498cd Michael Hanselmann
  else:
930 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
931 28b498cd Michael Hanselmann
932 28b498cd Michael Hanselmann
933 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
934 95b2e626 Michael Hanselmann
  """Watcher operations.
935 95b2e626 Michael Hanselmann

936 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
937 95b2e626 Michael Hanselmann
  @type args: list
938 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
939 95b2e626 Michael Hanselmann
  @rtype: int
940 95b2e626 Michael Hanselmann
  @return: the desired exit code
941 95b2e626 Michael Hanselmann

942 95b2e626 Michael Hanselmann
  """
943 95b2e626 Michael Hanselmann
  command = args[0]
944 95b2e626 Michael Hanselmann
  client = GetClient()
945 95b2e626 Michael Hanselmann
946 95b2e626 Michael Hanselmann
  if command == "continue":
947 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
948 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
949 95b2e626 Michael Hanselmann
950 95b2e626 Michael Hanselmann
  elif command == "pause":
951 95b2e626 Michael Hanselmann
    if len(args) < 2:
952 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
953 95b2e626 Michael Hanselmann
954 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
955 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
956 95b2e626 Michael Hanselmann
957 95b2e626 Michael Hanselmann
  elif command == "info":
958 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
959 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
960 95b2e626 Michael Hanselmann
961 95b2e626 Michael Hanselmann
  else:
962 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
963 debac808 Iustin Pop
                               errors.ECODE_INVAL)
964 95b2e626 Michael Hanselmann
965 95b2e626 Michael Hanselmann
  return 0
966 95b2e626 Michael Hanselmann
967 95b2e626 Michael Hanselmann
968 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
969 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
970 66d1f035 René Nussbaumer

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

976 66d1f035 René Nussbaumer
  """
977 66d1f035 René Nussbaumer
  if power:
978 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
979 66d1f035 René Nussbaumer
  else:
980 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
981 66d1f035 René Nussbaumer
982 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
983 66d1f035 René Nussbaumer
                            command=command,
984 66d1f035 René Nussbaumer
                            ignore_status=True,
985 cfed3b9f René Nussbaumer
                            timeout=opts.oob_timeout,
986 cfed3b9f René Nussbaumer
                            power_delay=opts.power_delay)
987 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
988 66d1f035 René Nussbaumer
  errs = 0
989 66d1f035 René Nussbaumer
  for node_result in result:
990 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
991 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
992 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
993 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
994 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
995 66d1f035 René Nussbaumer
      errs += 1
996 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
997 66d1f035 René Nussbaumer
               node_name)
998 66d1f035 René Nussbaumer
999 66d1f035 René Nussbaumer
  if errs > 0:
1000 66d1f035 René Nussbaumer
    return False
1001 66d1f035 René Nussbaumer
1002 66d1f035 René Nussbaumer
  return True
1003 66d1f035 René Nussbaumer
1004 66d1f035 René Nussbaumer
1005 3e0ed18c René Nussbaumer
def _InstanceStart(opts, inst_list, start, no_remember=False):
1006 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
1007 66d1f035 René Nussbaumer

1008 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1009 66d1f035 René Nussbaumer
  @param inst_list: The list of instances to operate on
1010 66d1f035 René Nussbaumer
  @param start: True if they should be started, False for shutdown
1011 3e0ed18c René Nussbaumer
  @param no_remember: If the instance state should be remembered
1012 66d1f035 René Nussbaumer
  @return: The success of the operation (none failed)
1013 66d1f035 René Nussbaumer

1014 66d1f035 René Nussbaumer
  """
1015 66d1f035 René Nussbaumer
  if start:
1016 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
1017 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
1018 66d1f035 René Nussbaumer
  else:
1019 fcecea0b René Nussbaumer
    opcls = compat.partial(opcodes.OpInstanceShutdown,
1020 3e0ed18c René Nussbaumer
                           timeout=opts.shutdown_timeout,
1021 3e0ed18c René Nussbaumer
                           no_remember=no_remember)
1022 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
1023 66d1f035 René Nussbaumer
1024 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
1025 66d1f035 René Nussbaumer
1026 66d1f035 René Nussbaumer
  for inst in inst_list:
1027 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
1028 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
1029 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
1030 66d1f035 René Nussbaumer
1031 66d1f035 René Nussbaumer
  results = jex.GetResults()
1032 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
1033 66d1f035 René Nussbaumer
1034 66d1f035 René Nussbaumer
  if bad_cnt == 0:
1035 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
1036 66d1f035 René Nussbaumer
  else:
1037 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
1038 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
1039 66d1f035 René Nussbaumer
             len(results))
1040 66d1f035 René Nussbaumer
    return False
1041 66d1f035 René Nussbaumer
1042 66d1f035 René Nussbaumer
  return True
1043 66d1f035 René Nussbaumer
1044 66d1f035 René Nussbaumer
1045 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
1046 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
1047 66d1f035 René Nussbaumer

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

1050 66d1f035 René Nussbaumer
  """
1051 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1052 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1053 66d1f035 René Nussbaumer
    """Init the object.
1054 66d1f035 René Nussbaumer

1055 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1056 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1057 66d1f035 René Nussbaumer
    @type node2ip: dict
1058 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1059 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1060 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1061 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1062 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1063 66d1f035 René Nussbaumer

1064 66d1f035 René Nussbaumer
    """
1065 66d1f035 René Nussbaumer
    self.down = set(node_list)
1066 66d1f035 René Nussbaumer
    self.up = set()
1067 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1068 66d1f035 René Nussbaumer
    self.success = True
1069 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1070 66d1f035 René Nussbaumer
    self.port = port
1071 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1072 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1073 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1074 66d1f035 René Nussbaumer
1075 66d1f035 René Nussbaumer
  def __call__(self):
1076 66d1f035 René Nussbaumer
    """When called we run action_cb.
1077 66d1f035 René Nussbaumer

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

1080 66d1f035 René Nussbaumer
    """
1081 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1082 66d1f035 René Nussbaumer
      self.success = False
1083 66d1f035 René Nussbaumer
1084 66d1f035 René Nussbaumer
    if self.down:
1085 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1086 66d1f035 René Nussbaumer
    else:
1087 66d1f035 René Nussbaumer
      return self.success
1088 66d1f035 René Nussbaumer
1089 66d1f035 René Nussbaumer
  def Wait(self, secs):
1090 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1091 66d1f035 René Nussbaumer

1092 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1093 66d1f035 René Nussbaumer

1094 66d1f035 René Nussbaumer
    """
1095 66d1f035 René Nussbaumer
    start = time.time()
1096 66d1f035 René Nussbaumer
    for node in self.down:
1097 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1098 66d1f035 René Nussbaumer
                       live_port_needed=True):
1099 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1100 66d1f035 René Nussbaumer
        self.up.add(node)
1101 66d1f035 René Nussbaumer
        self.down -= self.up
1102 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1103 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1104 66d1f035 René Nussbaumer
        return
1105 66d1f035 René Nussbaumer
1106 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1107 66d1f035 René Nussbaumer
1108 66d1f035 René Nussbaumer
1109 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1110 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1111 66d1f035 René Nussbaumer

1112 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1113 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1114 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1115 66d1f035 René Nussbaumer

1116 66d1f035 René Nussbaumer
  """
1117 66d1f035 René Nussbaumer
  client = GetClient()
1118 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1119 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1120 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1121 66d1f035 René Nussbaumer
  else:
1122 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1123 66d1f035 René Nussbaumer
1124 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1125 66d1f035 René Nussbaumer
                 for node in node_list)
1126 66d1f035 René Nussbaumer
1127 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1128 8e74adce René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port,
1129 8e74adce René Nussbaumer
                                        ToStdout)
1130 66d1f035 René Nussbaumer
1131 66d1f035 René Nussbaumer
  try:
1132 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1133 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1134 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1135 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1136 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1137 66d1f035 René Nussbaumer
    return False
1138 66d1f035 René Nussbaumer
1139 66d1f035 René Nussbaumer
1140 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1141 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1142 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1143 66d1f035 René Nussbaumer

1144 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1145 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1146 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1147 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1148 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1149 66d1f035 René Nussbaumer

1150 66d1f035 René Nussbaumer
  """
1151 66d1f035 René Nussbaumer
  start_inst_list = []
1152 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1153 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1154 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1155 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1156 66d1f035 René Nussbaumer
1157 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1158 66d1f035 René Nussbaumer
    del inst_map[inst]
1159 66d1f035 René Nussbaumer
1160 66d1f035 René Nussbaumer
  if start_inst_list:
1161 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1162 66d1f035 René Nussbaumer
1163 66d1f035 René Nussbaumer
  return True
1164 66d1f035 René Nussbaumer
1165 66d1f035 René Nussbaumer
1166 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1167 66d1f035 René Nussbaumer
  """Does the actual power on.
1168 66d1f035 René Nussbaumer

1169 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1170 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1171 66d1f035 René Nussbaumer
                         OOB)
1172 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1173 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1174 66d1f035 René Nussbaumer
  @return: The desired exit status
1175 66d1f035 René Nussbaumer

1176 66d1f035 René Nussbaumer
  """
1177 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1178 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1179 66d1f035 René Nussbaumer
             " manually if needed")
1180 66d1f035 René Nussbaumer
1181 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1182 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1183 66d1f035 René Nussbaumer
1184 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1185 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1186 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1187 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1188 66d1f035 René Nussbaumer
1189 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1190 66d1f035 René Nussbaumer
1191 66d1f035 René Nussbaumer
1192 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1193 66d1f035 René Nussbaumer
  """Does the actual power off.
1194 66d1f035 René Nussbaumer

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

1200 66d1f035 René Nussbaumer
  """
1201 3e0ed18c René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False, no_remember=True):
1202 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1203 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1204 66d1f035 René Nussbaumer
1205 66d1f035 René Nussbaumer
  if not node_list:
1206 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1207 66d1f035 René Nussbaumer
1208 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1209 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1210 66d1f035 René Nussbaumer
  else:
1211 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1212 66d1f035 René Nussbaumer
1213 66d1f035 René Nussbaumer
1214 66d1f035 René Nussbaumer
def Epo(opts, args):
1215 66d1f035 René Nussbaumer
  """EPO operations.
1216 66d1f035 René Nussbaumer

1217 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1218 66d1f035 René Nussbaumer
  @type args: list
1219 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1220 66d1f035 René Nussbaumer
  @rtype: int
1221 66d1f035 René Nussbaumer
  @return: the desired exit code
1222 66d1f035 René Nussbaumer

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