Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 66d1f035

History | View | Annotate | Download (41.5 kB)

1 7b3e7d41 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 afc3c260 Iustin Pop
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 7260cfbe Iustin Pop
"""Cluster related commands"""
22 a8083063 Iustin Pop
23 2d54e29c Iustin Pop
# pylint: disable-msg=W0401,W0613,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2d54e29c Iustin Pop
# W0613: Unused argument, since all functions follow the same API
26 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
27 7260cfbe Iustin Pop
# C0103: Invalid name gnt-cluster
28 2f79bd34 Iustin Pop
29 b3989551 Iustin Pop
import os.path
30 95b2e626 Michael Hanselmann
import time
31 6d4a1656 Michael Hanselmann
import OpenSSL
32 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 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
149 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
150 ce735215 Guido Trotter
                        beparams=beparams,
151 b6a30b0d Guido Trotter
                        nicparams=nicparams,
152 6204ee71 René Nussbaumer
                        ndparams=ndparams,
153 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
154 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
155 b989b9d9 Ken Wehr
                        modify_ssh_setup=opts.modify_ssh_setup,
156 3953242f Iustin Pop
                        maintain_node_health=opts.maintain_node_health,
157 ed14ed48 Luca Bigliardi
                        drbd_helper=drbd_helper,
158 39b0f0c2 Balazs Lecz
                        uid_pool=uid_pool,
159 bf4af505 Apollon Oikonomopoulos
                        default_iallocator=opts.default_iallocator,
160 e7323b5e Manuel Franceschini
                        primary_ip_version=primary_ip_version,
161 b18ecea2 René Nussbaumer
                        prealloc_wipe_disks=opts.prealloc_wipe_disks,
162 ce735215 Guido Trotter
                        )
163 bc84ffa7 Iustin Pop
  op = opcodes.OpClusterPostInit()
164 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
165 a8083063 Iustin Pop
  return 0
166 a8083063 Iustin Pop
167 a8083063 Iustin Pop
168 4331f6cd Michael Hanselmann
@UsesRPC
169 a8083063 Iustin Pop
def DestroyCluster(opts, args):
170 a8083063 Iustin Pop
  """Destroy the cluster.
171 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

410 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
411 469ee405 Iustin Pop
  @type args: list
412 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
413 469ee405 Iustin Pop
  @rtype: int
414 469ee405 Iustin Pop
  @return: the desired exit code
415 a8083063 Iustin Pop

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

446 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
447 469ee405 Iustin Pop
  @type args: list
448 469ee405 Iustin Pop
  @param args: should be an empty list
449 469ee405 Iustin Pop
  @rtype: int
450 469ee405 Iustin Pop
  @return: the desired exit code
451 a8083063 Iustin Pop

452 a8083063 Iustin Pop
  """
453 8d59409f Iustin Pop
  skip_checks = []
454 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
455 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
456 a3d32770 Iustin Pop
  op = opcodes.OpClusterVerify(skip_checks=skip_checks,
457 7c874ee1 Iustin Pop
                               verbose=opts.verbose,
458 a0c9776a Iustin Pop
                               error_codes=opts.error_codes,
459 a0c9776a Iustin Pop
                               debug_simulate_errors=opts.simulate_errors)
460 400ca2f7 Iustin Pop
  if SubmitOpCode(op, opts=opts):
461 34290825 Michael Hanselmann
    return 0
462 34290825 Michael Hanselmann
  else:
463 34290825 Michael Hanselmann
    return 1
464 a8083063 Iustin Pop
465 a8083063 Iustin Pop
466 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
467 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
468 f4d4e184 Iustin Pop

469 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
470 469ee405 Iustin Pop
  @type args: list
471 469ee405 Iustin Pop
  @param args: should be an empty list
472 469ee405 Iustin Pop
  @rtype: int
473 469ee405 Iustin Pop
  @return: the desired exit code
474 f4d4e184 Iustin Pop

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

532 60975797 Iustin Pop
  @param opts: the command line options selected by the user
533 60975797 Iustin Pop
  @type args: list
534 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
535 60975797 Iustin Pop
  @rtype: int
536 60975797 Iustin Pop
  @return: the desired exit code
537 60975797 Iustin Pop

538 60975797 Iustin Pop
  """
539 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
540 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
541 60975797 Iustin Pop
542 60975797 Iustin Pop
543 4331f6cd Michael Hanselmann
@UsesRPC
544 a8083063 Iustin Pop
def MasterFailover(opts, args):
545 a8083063 Iustin Pop
  """Failover the master node.
546 a8083063 Iustin Pop

547 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
548 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
549 a8083063 Iustin Pop
  master.
550 a8083063 Iustin Pop

551 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
552 469ee405 Iustin Pop
  @type args: list
553 469ee405 Iustin Pop
  @param args: should be an empty list
554 469ee405 Iustin Pop
  @rtype: int
555 469ee405 Iustin Pop
  @return: the desired exit code
556 469ee405 Iustin Pop

557 a8083063 Iustin Pop
  """
558 8e2524c3 Guido Trotter
  if opts.no_voting:
559 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
560 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
561 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
562 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
563 8e2524c3 Guido Trotter
    if not AskUser(usertext):
564 8e2524c3 Guido Trotter
      return 1
565 8e2524c3 Guido Trotter
566 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
567 a8083063 Iustin Pop
568 a8083063 Iustin Pop
569 4404ffad Iustin Pop
def MasterPing(opts, args):
570 4404ffad Iustin Pop
  """Checks if the master is alive.
571 4404ffad Iustin Pop

572 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
573 4404ffad Iustin Pop
  @type args: list
574 4404ffad Iustin Pop
  @param args: should be an empty list
575 4404ffad Iustin Pop
  @rtype: int
576 4404ffad Iustin Pop
  @return: the desired exit code
577 4404ffad Iustin Pop

578 4404ffad Iustin Pop
  """
579 4404ffad Iustin Pop
  try:
580 4404ffad Iustin Pop
    cl = GetClient()
581 4404ffad Iustin Pop
    cl.QueryClusterInfo()
582 4404ffad Iustin Pop
    return 0
583 4404ffad Iustin Pop
  except Exception: # pylint: disable-msg=W0703
584 4404ffad Iustin Pop
    return 1
585 4404ffad Iustin Pop
586 4404ffad Iustin Pop
587 73415719 Iustin Pop
def SearchTags(opts, args):
588 73415719 Iustin Pop
  """Searches the tags on all the cluster.
589 73415719 Iustin Pop

590 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
591 469ee405 Iustin Pop
  @type args: list
592 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
593 469ee405 Iustin Pop
  @rtype: int
594 469ee405 Iustin Pop
  @return: the desired exit code
595 469ee405 Iustin Pop

596 73415719 Iustin Pop
  """
597 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
598 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
599 73415719 Iustin Pop
  if not result:
600 73415719 Iustin Pop
    return 1
601 73415719 Iustin Pop
  result = list(result)
602 73415719 Iustin Pop
  result.sort()
603 73415719 Iustin Pop
  for path, tag in result:
604 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
605 73415719 Iustin Pop
606 73415719 Iustin Pop
607 6d4a1656 Michael Hanselmann
def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
608 3db3eb2a Michael Hanselmann
                 new_confd_hmac_key, new_cds, cds_filename,
609 3db3eb2a Michael Hanselmann
                 force):
610 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
611 6d4a1656 Michael Hanselmann

612 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
613 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
614 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
615 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
616 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
617 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
618 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
619 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
620 3db3eb2a Michael Hanselmann
  @type new_cds: bool
621 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
622 3db3eb2a Michael Hanselmann
  @type cds_filename: string
623 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
624 6d4a1656 Michael Hanselmann
  @type force: bool
625 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
626 6d4a1656 Michael Hanselmann

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

717 6d4a1656 Michael Hanselmann
  """
718 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
719 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
720 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
721 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
722 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
723 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
724 6d4a1656 Michael Hanselmann
                      opts.force)
725 6d4a1656 Michael Hanselmann
726 6d4a1656 Michael Hanselmann
727 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
728 90b6aa3a Manuel Franceschini
  """Modify the cluster.
729 90b6aa3a Manuel Franceschini

730 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
731 469ee405 Iustin Pop
  @type args: list
732 469ee405 Iustin Pop
  @param args: should be an empty list
733 469ee405 Iustin Pop
  @rtype: int
734 469ee405 Iustin Pop
  @return: the desired exit code
735 90b6aa3a Manuel Franceschini

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

832 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
833 469ee405 Iustin Pop
  @type args: list
834 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
835 469ee405 Iustin Pop
  @rtype: int
836 469ee405 Iustin Pop
  @return: the desired exit code
837 469ee405 Iustin Pop

838 3ccafd0e Iustin Pop
  """
839 3ccafd0e Iustin Pop
  command = args[0]
840 3ccafd0e Iustin Pop
  client = GetClient()
841 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
842 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
843 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
844 3ccafd0e Iustin Pop
  elif command == "info":
845 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
846 3ccafd0e Iustin Pop
    if result[0]:
847 3a24c527 Iustin Pop
      val = "set"
848 3ccafd0e Iustin Pop
    else:
849 3a24c527 Iustin Pop
      val = "unset"
850 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
851 2e668b38 Guido Trotter
  else:
852 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
853 debac808 Iustin Pop
                               errors.ECODE_INVAL)
854 2e668b38 Guido Trotter
855 3ccafd0e Iustin Pop
  return 0
856 3ccafd0e Iustin Pop
857 95b2e626 Michael Hanselmann
858 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
859 28b498cd Michael Hanselmann
  if until is None or until < time.time():
860 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
861 28b498cd Michael Hanselmann
  else:
862 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
863 28b498cd Michael Hanselmann
864 28b498cd Michael Hanselmann
865 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
866 95b2e626 Michael Hanselmann
  """Watcher operations.
867 95b2e626 Michael Hanselmann

868 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
869 95b2e626 Michael Hanselmann
  @type args: list
870 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
871 95b2e626 Michael Hanselmann
  @rtype: int
872 95b2e626 Michael Hanselmann
  @return: the desired exit code
873 95b2e626 Michael Hanselmann

874 95b2e626 Michael Hanselmann
  """
875 95b2e626 Michael Hanselmann
  command = args[0]
876 95b2e626 Michael Hanselmann
  client = GetClient()
877 95b2e626 Michael Hanselmann
878 95b2e626 Michael Hanselmann
  if command == "continue":
879 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
880 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
881 95b2e626 Michael Hanselmann
882 95b2e626 Michael Hanselmann
  elif command == "pause":
883 95b2e626 Michael Hanselmann
    if len(args) < 2:
884 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
885 95b2e626 Michael Hanselmann
886 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
887 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
888 95b2e626 Michael Hanselmann
889 95b2e626 Michael Hanselmann
  elif command == "info":
890 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
891 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
892 95b2e626 Michael Hanselmann
893 95b2e626 Michael Hanselmann
  else:
894 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
895 debac808 Iustin Pop
                               errors.ECODE_INVAL)
896 95b2e626 Michael Hanselmann
897 95b2e626 Michael Hanselmann
  return 0
898 95b2e626 Michael Hanselmann
899 95b2e626 Michael Hanselmann
900 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
901 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
902 66d1f035 René Nussbaumer

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

908 66d1f035 René Nussbaumer
  """
909 66d1f035 René Nussbaumer
  if power:
910 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
911 66d1f035 René Nussbaumer
  else:
912 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
913 66d1f035 René Nussbaumer
914 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
915 66d1f035 René Nussbaumer
                            command=command,
916 66d1f035 René Nussbaumer
                            ignore_status=True,
917 66d1f035 René Nussbaumer
                            timeout=opts.oob_timeout)
918 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
919 66d1f035 René Nussbaumer
  errs = 0
920 66d1f035 René Nussbaumer
  for node_result in result:
921 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
922 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
923 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
924 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
925 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
926 66d1f035 René Nussbaumer
      errs += 1
927 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
928 66d1f035 René Nussbaumer
               node_name)
929 66d1f035 René Nussbaumer
930 66d1f035 René Nussbaumer
  if errs > 0:
931 66d1f035 René Nussbaumer
    return False
932 66d1f035 René Nussbaumer
933 66d1f035 René Nussbaumer
  return True
934 66d1f035 René Nussbaumer
935 66d1f035 René Nussbaumer
936 66d1f035 René Nussbaumer
def _InstanceStart(opts, inst_list, start):
937 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
938 66d1f035 René Nussbaumer

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

944 66d1f035 René Nussbaumer
  """
945 66d1f035 René Nussbaumer
  if start:
946 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
947 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
948 66d1f035 René Nussbaumer
  else:
949 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceShutdown
950 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
951 66d1f035 René Nussbaumer
952 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
953 66d1f035 René Nussbaumer
954 66d1f035 René Nussbaumer
  for inst in inst_list:
955 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
956 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
957 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
958 66d1f035 René Nussbaumer
959 66d1f035 René Nussbaumer
  results = jex.GetResults()
960 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
961 66d1f035 René Nussbaumer
962 66d1f035 René Nussbaumer
  if bad_cnt == 0:
963 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
964 66d1f035 René Nussbaumer
  else:
965 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
966 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
967 66d1f035 René Nussbaumer
             len(results))
968 66d1f035 René Nussbaumer
    return False
969 66d1f035 René Nussbaumer
970 66d1f035 René Nussbaumer
  return True
971 66d1f035 René Nussbaumer
972 66d1f035 René Nussbaumer
973 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
974 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
975 66d1f035 René Nussbaumer

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

978 66d1f035 René Nussbaumer
  """
979 66d1f035 René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port,
980 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
981 66d1f035 René Nussbaumer
    """Init the object.
982 66d1f035 René Nussbaumer

983 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
984 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
985 66d1f035 René Nussbaumer
    @type node2ip: dict
986 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
987 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
988 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
989 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
990 66d1f035 René Nussbaumer

991 66d1f035 René Nussbaumer
    """
992 66d1f035 René Nussbaumer
    self.down = set(node_list)
993 66d1f035 René Nussbaumer
    self.up = set()
994 66d1f035 René Nussbaumer
    self.node2ip = node2ip
995 66d1f035 René Nussbaumer
    self.success = True
996 66d1f035 René Nussbaumer
    self.action_cb = action_cb
997 66d1f035 René Nussbaumer
    self.port = port
998 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
999 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1000 66d1f035 René Nussbaumer
1001 66d1f035 René Nussbaumer
  def __call__(self):
1002 66d1f035 René Nussbaumer
    """When called we run action_cb.
1003 66d1f035 René Nussbaumer

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

1006 66d1f035 René Nussbaumer
    """
1007 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1008 66d1f035 René Nussbaumer
      self.success = False
1009 66d1f035 René Nussbaumer
1010 66d1f035 René Nussbaumer
    if self.down:
1011 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1012 66d1f035 René Nussbaumer
    else:
1013 66d1f035 René Nussbaumer
      return self.success
1014 66d1f035 René Nussbaumer
1015 66d1f035 René Nussbaumer
  def Wait(self, secs):
1016 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1017 66d1f035 René Nussbaumer

1018 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1019 66d1f035 René Nussbaumer

1020 66d1f035 René Nussbaumer
    """
1021 66d1f035 René Nussbaumer
    start = time.time()
1022 66d1f035 René Nussbaumer
    for node in self.down:
1023 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1024 66d1f035 René Nussbaumer
                       live_port_needed=True):
1025 66d1f035 René Nussbaumer
        ToStdout("Node %s became available", node)
1026 66d1f035 René Nussbaumer
        self.up.add(node)
1027 66d1f035 René Nussbaumer
        self.down -= self.up
1028 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1029 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1030 66d1f035 René Nussbaumer
        return
1031 66d1f035 René Nussbaumer
1032 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1033 66d1f035 René Nussbaumer
1034 66d1f035 René Nussbaumer
1035 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1036 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1037 66d1f035 René Nussbaumer

1038 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1039 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1040 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1041 66d1f035 René Nussbaumer

1042 66d1f035 René Nussbaumer
  """
1043 66d1f035 René Nussbaumer
  client = GetClient()
1044 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1045 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1046 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1047 66d1f035 René Nussbaumer
  else:
1048 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1049 66d1f035 René Nussbaumer
1050 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1051 66d1f035 René Nussbaumer
                 for node in node_list)
1052 66d1f035 René Nussbaumer
1053 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1054 66d1f035 René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port)
1055 66d1f035 René Nussbaumer
1056 66d1f035 René Nussbaumer
  try:
1057 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1058 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1059 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1060 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1061 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1062 66d1f035 René Nussbaumer
    return False
1063 66d1f035 René Nussbaumer
1064 66d1f035 René Nussbaumer
1065 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1066 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1067 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1068 66d1f035 René Nussbaumer

1069 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1070 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1071 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1072 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1073 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1074 66d1f035 René Nussbaumer

1075 66d1f035 René Nussbaumer
  """
1076 66d1f035 René Nussbaumer
  start_inst_list = []
1077 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1078 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1079 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1080 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1081 66d1f035 René Nussbaumer
1082 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1083 66d1f035 René Nussbaumer
    del inst_map[inst]
1084 66d1f035 René Nussbaumer
1085 66d1f035 René Nussbaumer
  if start_inst_list:
1086 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1087 66d1f035 René Nussbaumer
1088 66d1f035 René Nussbaumer
  return True
1089 66d1f035 René Nussbaumer
1090 66d1f035 René Nussbaumer
1091 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1092 66d1f035 René Nussbaumer
  """Does the actual power on.
1093 66d1f035 René Nussbaumer

1094 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1095 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1096 66d1f035 René Nussbaumer
                         OOB)
1097 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1098 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1099 66d1f035 René Nussbaumer
  @return: The desired exit status
1100 66d1f035 René Nussbaumer

1101 66d1f035 René Nussbaumer
  """
1102 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1103 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1104 66d1f035 René Nussbaumer
             " manually if needed")
1105 66d1f035 René Nussbaumer
1106 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1107 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1108 66d1f035 René Nussbaumer
1109 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1110 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1111 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1112 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1113 66d1f035 René Nussbaumer
1114 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1115 66d1f035 René Nussbaumer
1116 66d1f035 René Nussbaumer
1117 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1118 66d1f035 René Nussbaumer
  """Does the actual power off.
1119 66d1f035 René Nussbaumer

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

1125 66d1f035 René Nussbaumer
  """
1126 66d1f035 René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False):
1127 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1128 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1129 66d1f035 René Nussbaumer
1130 66d1f035 René Nussbaumer
  if not node_list:
1131 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1132 66d1f035 René Nussbaumer
1133 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1134 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1135 66d1f035 René Nussbaumer
  else:
1136 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1137 66d1f035 René Nussbaumer
1138 66d1f035 René Nussbaumer
1139 66d1f035 René Nussbaumer
def Epo(opts, args):
1140 66d1f035 René Nussbaumer
  """EPO operations.
1141 66d1f035 René Nussbaumer

1142 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1143 66d1f035 René Nussbaumer
  @type args: list
1144 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1145 66d1f035 René Nussbaumer
  @rtype: int
1146 66d1f035 René Nussbaumer
  @return: the desired exit code
1147 66d1f035 René Nussbaumer

1148 66d1f035 René Nussbaumer
  """
1149 66d1f035 René Nussbaumer
  if opts.groups and opts.show_all:
1150 66d1f035 René Nussbaumer
    ToStderr("Only one of --groups or --all are allowed")
1151 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1152 66d1f035 René Nussbaumer
  elif args and opts.show_all:
1153 66d1f035 René Nussbaumer
    ToStderr("Arguments in combination with --all are not allowed")
1154 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1155 66d1f035 René Nussbaumer
1156 66d1f035 René Nussbaumer
  client = GetClient()
1157 66d1f035 René Nussbaumer
1158 66d1f035 René Nussbaumer
  if opts.groups:
1159 66d1f035 René Nussbaumer
    node_query_list = itertools.chain(*client.QueryGroups(names=args,
1160 66d1f035 René Nussbaumer
                                                          fields=["node_list"],
1161 66d1f035 René Nussbaumer
                                                          use_locking=False))
1162 66d1f035 René Nussbaumer
  else:
1163 66d1f035 René Nussbaumer
    node_query_list = args
1164 66d1f035 René Nussbaumer
1165 66d1f035 René Nussbaumer
  result = client.QueryNodes(names=node_query_list,
1166 66d1f035 René Nussbaumer
                             fields=["name", "master", "pinst_list",
1167 66d1f035 René Nussbaumer
                                     "sinst_list", "powered", "offline"],
1168 66d1f035 René Nussbaumer
                             use_locking=False)
1169 66d1f035 René Nussbaumer
  node_list = []
1170 66d1f035 René Nussbaumer
  inst_map = {}
1171 66d1f035 René Nussbaumer
  for (idx, (node, master, pinsts, sinsts, powered,
1172 66d1f035 René Nussbaumer
             offline)) in enumerate(result):
1173 66d1f035 René Nussbaumer
    # Normalize the node_query_list as well
1174 66d1f035 René Nussbaumer
    if not opts.show_all:
1175 66d1f035 René Nussbaumer
      node_query_list[idx] = node
1176 66d1f035 René Nussbaumer
    if not offline:
1177 66d1f035 René Nussbaumer
      for inst in (pinsts + sinsts):
1178 66d1f035 René Nussbaumer
        if inst in inst_map:
1179 66d1f035 René Nussbaumer
          if not master:
1180 66d1f035 René Nussbaumer
            inst_map[inst].add(node)
1181 66d1f035 René Nussbaumer
        elif master:
1182 66d1f035 René Nussbaumer
          inst_map[inst] = set()
1183 66d1f035 René Nussbaumer
        else:
1184 66d1f035 René Nussbaumer
          inst_map[inst] = set([node])
1185 66d1f035 René Nussbaumer
1186 66d1f035 René Nussbaumer
    if master and opts.on:
1187 66d1f035 René Nussbaumer
      # We ignore the master for turning on the machines, in fact we are
1188 66d1f035 René Nussbaumer
      # already operating on the master at this point :)
1189 66d1f035 René Nussbaumer
      continue
1190 66d1f035 René Nussbaumer
    elif master and not opts.show_all:
1191 66d1f035 René Nussbaumer
      ToStderr("%s is the master node, please do a master-failover to another"
1192 66d1f035 René Nussbaumer
               " node not affected by the EPO or use --all if you intend to"
1193 66d1f035 René Nussbaumer
               " shutdown the whole cluster", node)
1194 66d1f035 René Nussbaumer
      return constants.EXIT_FAILURE
1195 66d1f035 René Nussbaumer
    elif powered is None:
1196 66d1f035 René Nussbaumer
      ToStdout("Node %s does not support out-of-band handling, it can not be"
1197 66d1f035 René Nussbaumer
               " handled in a fully automated manner", node)
1198 66d1f035 René Nussbaumer
    elif powered == opts.on:
1199 66d1f035 René Nussbaumer
      ToStdout("Node %s is already in desired power state, skipping", node)
1200 66d1f035 René Nussbaumer
    elif not offline or (offline and powered):
1201 66d1f035 René Nussbaumer
      node_list.append(node)
1202 66d1f035 René Nussbaumer
1203 66d1f035 René Nussbaumer
  if not opts.force and not ConfirmOperation(node_query_list, "nodes", "epo"):
1204 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1205 66d1f035 René Nussbaumer
1206 66d1f035 René Nussbaumer
  if opts.on:
1207 66d1f035 René Nussbaumer
    return _EpoOn(opts, node_query_list, node_list, inst_map)
1208 66d1f035 René Nussbaumer
  else:
1209 66d1f035 René Nussbaumer
    return _EpoOff(opts, node_list, inst_map)
1210 66d1f035 René Nussbaumer
1211 66d1f035 René Nussbaumer
1212 a8083063 Iustin Pop
commands = {
1213 6ea815cf Iustin Pop
  'init': (
1214 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
1215 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
1216 6ea815cf Iustin Pop
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
1217 b989b9d9 Ken Wehr
     NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
1218 39b0f0c2 Balazs Lecz
     SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
1219 bf4af505 Apollon Oikonomopoulos
     UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
1220 6204ee71 René Nussbaumer
     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
1221 6204ee71 René Nussbaumer
     NODE_PARAMS_OPT],
1222 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
1223 6ea815cf Iustin Pop
  'destroy': (
1224 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
1225 6ea815cf Iustin Pop
    "", "Destroy cluster"),
1226 6ea815cf Iustin Pop
  'rename': (
1227 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
1228 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
1229 6ea815cf Iustin Pop
    "<new_name>",
1230 6ea815cf Iustin Pop
    "Renames the cluster"),
1231 6ea815cf Iustin Pop
  'redist-conf': (
1232 aa06f8c6 Michael Hanselmann
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1233 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
1234 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
1235 6ea815cf Iustin Pop
  'verify': (
1236 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
1237 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
1238 aa06f8c6 Michael Hanselmann
     DRY_RUN_OPT, PRIORITY_OPT],
1239 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
1240 6ea815cf Iustin Pop
  'verify-disks': (
1241 aa06f8c6 Michael Hanselmann
    VerifyDisks, ARGS_NONE, [PRIORITY_OPT],
1242 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
1243 6ea815cf Iustin Pop
  'repair-disk-sizes': (
1244 aa06f8c6 Michael Hanselmann
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
1245 6ea815cf Iustin Pop
    "", "Updates mismatches in recorded disk sizes"),
1246 c28502b1 Iustin Pop
  'master-failover': (
1247 064c21f8 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT],
1248 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
1249 4404ffad Iustin Pop
  'master-ping': (
1250 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
1251 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
1252 6ea815cf Iustin Pop
  'version': (
1253 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
1254 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
1255 6ea815cf Iustin Pop
  'getmaster': (
1256 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
1257 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
1258 6ea815cf Iustin Pop
  'copyfile': (
1259 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
1260 74adc100 Iustin Pop
    [NODE_LIST_OPT, USE_REPL_NET_OPT],
1261 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
1262 6ea815cf Iustin Pop
  'command': (
1263 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
1264 064c21f8 Iustin Pop
    [NODE_LIST_OPT],
1265 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
1266 6ea815cf Iustin Pop
  'info': (
1267 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
1268 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
1269 6ea815cf Iustin Pop
  'list-tags': (
1270 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
1271 6ea815cf Iustin Pop
  'add-tags': (
1272 aa06f8c6 Michael Hanselmann
    AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
1273 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
1274 6ea815cf Iustin Pop
  'remove-tags': (
1275 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
1276 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
1277 6ea815cf Iustin Pop
  'search-tags': (
1278 aa06f8c6 Michael Hanselmann
    SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "",
1279 aa06f8c6 Michael Hanselmann
    "Searches the tags on all objects on"
1280 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
1281 6ea815cf Iustin Pop
  'queue': (
1282 6ea815cf Iustin Pop
    QueueOps,
1283 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
1284 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
1285 6ea815cf Iustin Pop
  'watcher': (
1286 6ea815cf Iustin Pop
    WatcherOps,
1287 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
1288 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
1289 064c21f8 Iustin Pop
    [],
1290 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
1291 6ea815cf Iustin Pop
  'modify': (
1292 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
1293 38f9d2cf Guido Trotter
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
1294 1338f2b4 Balazs Lecz
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
1295 ed14ed48 Luca Bigliardi
     UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT,
1296 db5a8a2d Iustin Pop
     NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT, RESERVED_LVS_OPT,
1297 6204ee71 René Nussbaumer
     DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT, NODE_PARAMS_OPT],
1298 6ea815cf Iustin Pop
    "[opts...]",
1299 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
1300 6d4a1656 Michael Hanselmann
  "renew-crypto": (
1301 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
1302 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
1303 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
1304 3db3eb2a Michael Hanselmann
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT],
1305 6d4a1656 Michael Hanselmann
    "[opts...]",
1306 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
1307 66d1f035 René Nussbaumer
  "epo": (
1308 66d1f035 René Nussbaumer
    Epo, [ArgUnknown()],
1309 66d1f035 René Nussbaumer
    [FORCE_OPT, ON_OPT, GROUPS_OPT, ALL_OPT, OOB_TIMEOUT_OPT],
1310 66d1f035 René Nussbaumer
    "[opts...] [args]",
1311 66d1f035 René Nussbaumer
    "Performs an emergency power-off on given args"),
1312 a8083063 Iustin Pop
  }
1313 a8083063 Iustin Pop
1314 6d4a1656 Michael Hanselmann
1315 c28502b1 Iustin Pop
#: dictionary with aliases for commands
1316 c28502b1 Iustin Pop
aliases = {
1317 c28502b1 Iustin Pop
  'masterfailover': 'master-failover',
1318 c28502b1 Iustin Pop
}
1319 c28502b1 Iustin Pop
1320 c28502b1 Iustin Pop
1321 7b3e7d41 Michael Hanselmann
def Main():
1322 7b3e7d41 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
1323 7b3e7d41 Michael Hanselmann
                     aliases=aliases)