Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (51.9 kB)

1 7b3e7d41 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 eeaa5f6c Bernardo Dal Seno
# Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013 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 78e706bb Michael Hanselmann
from ganeti import pathutils
46 66d1f035 René Nussbaumer
47 66d1f035 René Nussbaumer
48 66d1f035 René Nussbaumer
ON_OPT = cli_option("--on", default=False,
49 66d1f035 René Nussbaumer
                    action="store_true", dest="on",
50 66d1f035 René Nussbaumer
                    help="Recover from an EPO")
51 66d1f035 René Nussbaumer
52 66d1f035 René Nussbaumer
GROUPS_OPT = cli_option("--groups", default=False,
53 5ae4945a Iustin Pop
                        action="store_true", dest="groups",
54 5ae4945a Iustin Pop
                        help="Arguments are node groups instead of nodes")
55 66d1f035 René Nussbaumer
56 6022a419 Iustin Pop
FORCE_FAILOVER = cli_option("--yes-do-it", dest="yes_do_it",
57 6022a419 Iustin Pop
                            help="Override interactive check for --no-voting",
58 6022a419 Iustin Pop
                            default=False, action="store_true")
59 6022a419 Iustin Pop
60 66d1f035 René Nussbaumer
_EPO_PING_INTERVAL = 30 # 30 seconds between pings
61 66d1f035 René Nussbaumer
_EPO_PING_TIMEOUT = 1 # 1 second
62 66d1f035 René Nussbaumer
_EPO_REACHABLE_TIMEOUT = 15 * 60 # 15 minutes
63 a8083063 Iustin Pop
64 a8083063 Iustin Pop
65 4331f6cd Michael Hanselmann
@UsesRPC
66 a8083063 Iustin Pop
def InitCluster(opts, args):
67 a8083063 Iustin Pop
  """Initialize the cluster.
68 a8083063 Iustin Pop

69 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
70 469ee405 Iustin Pop
  @type args: list
71 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
72 469ee405 Iustin Pop
      cluster name
73 469ee405 Iustin Pop
  @rtype: int
74 469ee405 Iustin Pop
  @return: the desired exit code
75 a8083063 Iustin Pop

76 a8083063 Iustin Pop
  """
77 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
78 3a24c527 Iustin Pop
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
79 90b6aa3a Manuel Franceschini
    return 1
80 90b6aa3a Manuel Franceschini
81 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
82 90b6aa3a Manuel Franceschini
  if opts.lvm_storage and not opts.vg_name:
83 90b6aa3a Manuel Franceschini
    vg_name = constants.DEFAULT_VG
84 90b6aa3a Manuel Franceschini
85 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
86 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
87 ed14ed48 Luca Bigliardi
    return 1
88 ed14ed48 Luca Bigliardi
89 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
90 ed14ed48 Luca Bigliardi
  if opts.drbd_storage and not opts.drbd_helper:
91 ed14ed48 Luca Bigliardi
    drbd_helper = constants.DEFAULT_DRBD_HELPER
92 ed14ed48 Luca Bigliardi
93 25be0c75 Guido Trotter
  master_netdev = opts.master_netdev
94 25be0c75 Guido Trotter
  if master_netdev is None:
95 25be0c75 Guido Trotter
    master_netdev = constants.DEFAULT_BRIDGE
96 25be0c75 Guido Trotter
97 ea3a925f Alexander Schreiber
  hvlist = opts.enabled_hypervisors
98 383a3591 Iustin Pop
  if hvlist is None:
99 383a3591 Iustin Pop
    hvlist = constants.DEFAULT_ENABLED_HYPERVISOR
100 066f465d Guido Trotter
  hvlist = hvlist.split(",")
101 ea3a925f Alexander Schreiber
102 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
103 ea3a925f Alexander Schreiber
  beparams = opts.beparams
104 b6a30b0d Guido Trotter
  nicparams = opts.nicparams
105 ea3a925f Alexander Schreiber
106 bc5d0215 Andrea Spadaccini
  diskparams = dict(opts.diskparams)
107 bc5d0215 Andrea Spadaccini
108 bc5d0215 Andrea Spadaccini
  # check the disk template types here, as we cannot rely on the type check done
109 bc5d0215 Andrea Spadaccini
  # by the opcode parameter types
110 bc5d0215 Andrea Spadaccini
  diskparams_keys = set(diskparams.keys())
111 bc5d0215 Andrea Spadaccini
  if not (diskparams_keys <= constants.DISK_TEMPLATES):
112 bc5d0215 Andrea Spadaccini
    unknown = utils.NiceSort(diskparams_keys - constants.DISK_TEMPLATES)
113 bc5d0215 Andrea Spadaccini
    ToStderr("Disk templates unknown: %s" % utils.CommaJoin(unknown))
114 bc5d0215 Andrea Spadaccini
    return 1
115 bc5d0215 Andrea Spadaccini
116 ea3a925f Alexander Schreiber
  # prepare beparams dict
117 d3cfe525 Guido Trotter
  beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams)
118 b2e233a5 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT)
119 ea3a925f Alexander Schreiber
120 b6a30b0d Guido Trotter
  # prepare nicparams dict
121 b6a30b0d Guido Trotter
  nicparams = objects.FillDict(constants.NICC_DEFAULTS, nicparams)
122 b6a30b0d Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
123 b6a30b0d Guido Trotter
124 6204ee71 René Nussbaumer
  # prepare ndparams dict
125 6204ee71 René Nussbaumer
  if opts.ndparams is None:
126 6204ee71 René Nussbaumer
    ndparams = dict(constants.NDC_DEFAULTS)
127 6204ee71 René Nussbaumer
  else:
128 6204ee71 René Nussbaumer
    ndparams = objects.FillDict(constants.NDC_DEFAULTS, opts.ndparams)
129 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
130 6204ee71 René Nussbaumer
131 ea3a925f Alexander Schreiber
  # prepare hvparams dict
132 ea3a925f Alexander Schreiber
  for hv in constants.HYPER_TYPES:
133 ea3a925f Alexander Schreiber
    if hv not in hvparams:
134 ea3a925f Alexander Schreiber
      hvparams[hv] = {}
135 d3cfe525 Guido Trotter
    hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv])
136 a5728081 Guido Trotter
    utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES)
137 ea3a925f Alexander Schreiber
138 bc5d0215 Andrea Spadaccini
  # prepare diskparams dict
139 bc5d0215 Andrea Spadaccini
  for templ in constants.DISK_TEMPLATES:
140 bc5d0215 Andrea Spadaccini
    if templ not in diskparams:
141 bc5d0215 Andrea Spadaccini
      diskparams[templ] = {}
142 bc5d0215 Andrea Spadaccini
    diskparams[templ] = objects.FillDict(constants.DISK_DT_DEFAULTS[templ],
143 bc5d0215 Andrea Spadaccini
                                         diskparams[templ])
144 bc5d0215 Andrea Spadaccini
    utils.ForceDictType(diskparams[templ], constants.DISK_DT_TYPES)
145 bc5d0215 Andrea Spadaccini
146 18bb6d28 Agata Murawska
  # prepare ipolicy dict
147 eeaa5f6c Bernardo Dal Seno
  ipolicy = CreateIPolicyFromOpts(
148 976b78ba Iustin Pop
    ispecs_mem_size=opts.ispecs_mem_size,
149 976b78ba Iustin Pop
    ispecs_cpu_count=opts.ispecs_cpu_count,
150 976b78ba Iustin Pop
    ispecs_disk_count=opts.ispecs_disk_count,
151 976b78ba Iustin Pop
    ispecs_disk_size=opts.ispecs_disk_size,
152 976b78ba Iustin Pop
    ispecs_nic_count=opts.ispecs_nic_count,
153 976b78ba Iustin Pop
    ipolicy_disk_templates=opts.ipolicy_disk_templates,
154 976b78ba Iustin Pop
    ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio,
155 31d827d1 René Nussbaumer
    ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio,
156 976b78ba Iustin Pop
    fill_all=True)
157 18bb6d28 Agata Murawska
158 e32df528 Iustin Pop
  if opts.candidate_pool_size is None:
159 e32df528 Iustin Pop
    opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT
160 e32df528 Iustin Pop
161 e3646f22 Iustin Pop
  if opts.mac_prefix is None:
162 e3646f22 Iustin Pop
    opts.mac_prefix = constants.DEFAULT_MAC_PREFIX
163 e3646f22 Iustin Pop
164 39b0f0c2 Balazs Lecz
  uid_pool = opts.uid_pool
165 39b0f0c2 Balazs Lecz
  if uid_pool is not None:
166 39b0f0c2 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
167 39b0f0c2 Balazs Lecz
168 b883637f René Nussbaumer
  if opts.prealloc_wipe_disks is None:
169 b883637f René Nussbaumer
    opts.prealloc_wipe_disks = False
170 b883637f René Nussbaumer
171 bf689b7a Andrea Spadaccini
  external_ip_setup_script = opts.use_external_mip_script
172 bf689b7a Andrea Spadaccini
  if external_ip_setup_script is None:
173 bf689b7a Andrea Spadaccini
    external_ip_setup_script = False
174 bf689b7a Andrea Spadaccini
175 e7323b5e Manuel Franceschini
  try:
176 e7323b5e Manuel Franceschini
    primary_ip_version = int(opts.primary_ip_version)
177 e7323b5e Manuel Franceschini
  except (ValueError, TypeError), err:
178 e7323b5e Manuel Franceschini
    ToStderr("Invalid primary ip version value: %s" % str(err))
179 e7323b5e Manuel Franceschini
    return 1
180 e7323b5e Manuel Franceschini
181 5a8648eb Andrea Spadaccini
  master_netmask = opts.master_netmask
182 5a8648eb Andrea Spadaccini
  try:
183 5a8648eb Andrea Spadaccini
    if master_netmask is not None:
184 5a8648eb Andrea Spadaccini
      master_netmask = int(master_netmask)
185 5a8648eb Andrea Spadaccini
  except (ValueError, TypeError), err:
186 5a8648eb Andrea Spadaccini
    ToStderr("Invalid master netmask value: %s" % str(err))
187 5a8648eb Andrea Spadaccini
    return 1
188 5a8648eb Andrea Spadaccini
189 c4929a8b René Nussbaumer
  if opts.disk_state:
190 c4929a8b René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
191 c4929a8b René Nussbaumer
  else:
192 c4929a8b René Nussbaumer
    disk_state = {}
193 c4929a8b René Nussbaumer
194 c4929a8b René Nussbaumer
  hv_state = dict(opts.hv_state)
195 c4929a8b René Nussbaumer
196 966e1580 Helga Velroyen
  enabled_disk_templates = opts.enabled_disk_templates
197 966e1580 Helga Velroyen
  if enabled_disk_templates:
198 966e1580 Helga Velroyen
    enabled_disk_templates = enabled_disk_templates.split(",")
199 966e1580 Helga Velroyen
  else:
200 966e1580 Helga Velroyen
    enabled_disk_templates = list(constants.DEFAULT_ENABLED_DISK_TEMPLATES)
201 966e1580 Helga Velroyen
202 a0c9f010 Michael Hanselmann
  bootstrap.InitCluster(cluster_name=args[0],
203 a0c9f010 Michael Hanselmann
                        secondary_ip=opts.secondary_ip,
204 a0c9f010 Michael Hanselmann
                        vg_name=vg_name,
205 a0c9f010 Michael Hanselmann
                        mac_prefix=opts.mac_prefix,
206 5a8648eb Andrea Spadaccini
                        master_netmask=master_netmask,
207 25be0c75 Guido Trotter
                        master_netdev=master_netdev,
208 ea3a925f Alexander Schreiber
                        file_storage_dir=opts.file_storage_dir,
209 7925d409 Apollon Oikonomopoulos
                        shared_file_storage_dir=opts.shared_file_storage_dir,
210 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
211 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
212 ce735215 Guido Trotter
                        beparams=beparams,
213 b6a30b0d Guido Trotter
                        nicparams=nicparams,
214 6204ee71 René Nussbaumer
                        ndparams=ndparams,
215 bc5d0215 Andrea Spadaccini
                        diskparams=diskparams,
216 18bb6d28 Agata Murawska
                        ipolicy=ipolicy,
217 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
218 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
219 b989b9d9 Ken Wehr
                        modify_ssh_setup=opts.modify_ssh_setup,
220 3953242f Iustin Pop
                        maintain_node_health=opts.maintain_node_health,
221 ed14ed48 Luca Bigliardi
                        drbd_helper=drbd_helper,
222 39b0f0c2 Balazs Lecz
                        uid_pool=uid_pool,
223 bf4af505 Apollon Oikonomopoulos
                        default_iallocator=opts.default_iallocator,
224 e7323b5e Manuel Franceschini
                        primary_ip_version=primary_ip_version,
225 b18ecea2 René Nussbaumer
                        prealloc_wipe_disks=opts.prealloc_wipe_disks,
226 bf689b7a Andrea Spadaccini
                        use_external_mip_script=external_ip_setup_script,
227 c4929a8b René Nussbaumer
                        hv_state=hv_state,
228 c4929a8b René Nussbaumer
                        disk_state=disk_state,
229 c074a9e8 Helga Velroyen
                        enabled_storage_types=enabled_storage_types,
230 ce735215 Guido Trotter
                        )
231 bc84ffa7 Iustin Pop
  op = opcodes.OpClusterPostInit()
232 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
233 a8083063 Iustin Pop
  return 0
234 a8083063 Iustin Pop
235 a8083063 Iustin Pop
236 4331f6cd Michael Hanselmann
@UsesRPC
237 a8083063 Iustin Pop
def DestroyCluster(opts, args):
238 a8083063 Iustin Pop
  """Destroy the cluster.
239 a8083063 Iustin Pop

240 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
241 469ee405 Iustin Pop
  @type args: list
242 469ee405 Iustin Pop
  @param args: should be an empty list
243 469ee405 Iustin Pop
  @rtype: int
244 469ee405 Iustin Pop
  @return: the desired exit code
245 098c0958 Michael Hanselmann

246 a8083063 Iustin Pop
  """
247 a8083063 Iustin Pop
  if not opts.yes_do_it:
248 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
249 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
250 a8083063 Iustin Pop
    return 1
251 a8083063 Iustin Pop
252 c6d43e9e Iustin Pop
  op = opcodes.OpClusterDestroy()
253 400ca2f7 Iustin Pop
  master = SubmitOpCode(op, opts=opts)
254 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
255 140aa4a8 Iustin Pop
  # shutdown all the daemons
256 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
257 a8083063 Iustin Pop
  return 0
258 a8083063 Iustin Pop
259 a8083063 Iustin Pop
260 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
261 07bd8a51 Iustin Pop
  """Rename the cluster.
262 07bd8a51 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 contain only one element, the new cluster name
266 469ee405 Iustin Pop
  @rtype: int
267 469ee405 Iustin Pop
  @return: the desired exit code
268 07bd8a51 Iustin Pop

269 07bd8a51 Iustin Pop
  """
270 6a016df9 Michael Hanselmann
  cl = GetClient()
271 6a016df9 Michael Hanselmann
272 6a016df9 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
273 6a016df9 Michael Hanselmann
274 6a016df9 Michael Hanselmann
  new_name = args[0]
275 07bd8a51 Iustin Pop
  if not opts.force:
276 6a016df9 Michael Hanselmann
    usertext = ("This will rename the cluster from '%s' to '%s'. If you are"
277 6a016df9 Michael Hanselmann
                " connected over the network to the cluster name, the"
278 6a016df9 Michael Hanselmann
                " operation is very dangerous as the IP address will be"
279 6a016df9 Michael Hanselmann
                " removed from the node and the change may not go through."
280 6a016df9 Michael Hanselmann
                " Continue?") % (cluster_name, new_name)
281 47988778 Iustin Pop
    if not AskUser(usertext):
282 07bd8a51 Iustin Pop
      return 1
283 07bd8a51 Iustin Pop
284 e126df25 Iustin Pop
  op = opcodes.OpClusterRename(name=new_name)
285 6a016df9 Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
286 6a016df9 Michael Hanselmann
287 48418fea Iustin Pop
  if result:
288 48418fea Iustin Pop
    ToStdout("Cluster renamed from '%s' to '%s'", cluster_name, result)
289 6a016df9 Michael Hanselmann
290 07bd8a51 Iustin Pop
  return 0
291 07bd8a51 Iustin Pop
292 07bd8a51 Iustin Pop
293 fb926117 Andrea Spadaccini
def ActivateMasterIp(opts, args):
294 fb926117 Andrea Spadaccini
  """Activates the master IP.
295 fb926117 Andrea Spadaccini

296 fb926117 Andrea Spadaccini
  """
297 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
298 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
299 fb926117 Andrea Spadaccini
  return 0
300 fb926117 Andrea Spadaccini
301 fb926117 Andrea Spadaccini
302 fb926117 Andrea Spadaccini
def DeactivateMasterIp(opts, args):
303 fb926117 Andrea Spadaccini
  """Deactivates the master IP.
304 fb926117 Andrea Spadaccini

305 fb926117 Andrea Spadaccini
  """
306 fb926117 Andrea Spadaccini
  if not opts.confirm:
307 fb926117 Andrea Spadaccini
    usertext = ("This will disable the master IP. All the open connections to"
308 fb926117 Andrea Spadaccini
                " the master IP will be closed. To reach the master you will"
309 fb926117 Andrea Spadaccini
                " need to use its node IP."
310 fb926117 Andrea Spadaccini
                " Continue?")
311 fb926117 Andrea Spadaccini
    if not AskUser(usertext):
312 fb926117 Andrea Spadaccini
      return 1
313 fb926117 Andrea Spadaccini
314 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterDeactivateMasterIp()
315 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
316 fb926117 Andrea Spadaccini
  return 0
317 fb926117 Andrea Spadaccini
318 fb926117 Andrea Spadaccini
319 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
320 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
321 afee0879 Iustin Pop

322 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
323 afee0879 Iustin Pop
  @type args: list
324 afee0879 Iustin Pop
  @param args: empty list
325 afee0879 Iustin Pop
  @rtype: int
326 afee0879 Iustin Pop
  @return: the desired exit code
327 afee0879 Iustin Pop

328 afee0879 Iustin Pop
  """
329 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
330 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
331 afee0879 Iustin Pop
  return 0
332 afee0879 Iustin Pop
333 afee0879 Iustin Pop
334 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
335 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
336 a8083063 Iustin Pop

337 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
338 469ee405 Iustin Pop
  @type args: list
339 469ee405 Iustin Pop
  @param args: should be an empty list
340 469ee405 Iustin Pop
  @rtype: int
341 469ee405 Iustin Pop
  @return: the desired exit code
342 a8083063 Iustin Pop

343 a8083063 Iustin Pop
  """
344 42ab9ac4 Iustin Pop
  cl = GetClient(query=True)
345 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
346 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
347 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
348 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
349 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
350 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
351 a8083063 Iustin Pop
  return 0
352 a8083063 Iustin Pop
353 a8083063 Iustin Pop
354 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
355 a8083063 Iustin Pop
  """Write name of master node to the standard output.
356 a8083063 Iustin Pop

357 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
358 469ee405 Iustin Pop
  @type args: list
359 469ee405 Iustin Pop
  @param args: should be an empty list
360 469ee405 Iustin Pop
  @rtype: int
361 469ee405 Iustin Pop
  @return: the desired exit code
362 a8083063 Iustin Pop

363 a8083063 Iustin Pop
  """
364 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
365 8eb148ae Iustin Pop
  ToStdout(master)
366 a8083063 Iustin Pop
  return 0
367 a8083063 Iustin Pop
368 cac599f1 Michael Hanselmann
369 0e79564a Bernardo Dal Seno
def _FormatGroupedParams(paramsdict, roman=False):
370 0e79564a Bernardo Dal Seno
  """Format Grouped parameters (be, nic, disk) by group.
371 1094acda Guido Trotter

372 1094acda Guido Trotter
  @type paramsdict: dict of dicts
373 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
374 0e79564a Bernardo Dal Seno
  @rtype: dict of dicts
375 0e79564a Bernardo Dal Seno
  @return: copy of the input dictionaries with strings as values
376 1094acda Guido Trotter

377 1094acda Guido Trotter
  """
378 0e79564a Bernardo Dal Seno
  ret = {}
379 0e79564a Bernardo Dal Seno
  for (item, val) in paramsdict.items():
380 664a9d73 René Nussbaumer
    if isinstance(val, dict):
381 0e79564a Bernardo Dal Seno
      ret[item] = _FormatGroupedParams(val, roman=roman)
382 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
383 0e79564a Bernardo Dal Seno
      ret[item] = compat.TryToRoman(val)
384 664a9d73 René Nussbaumer
    else:
385 0e79564a Bernardo Dal Seno
      ret[item] = str(val)
386 0e79564a Bernardo Dal Seno
  return ret
387 a8083063 Iustin Pop
388 cac599f1 Michael Hanselmann
389 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
390 a8083063 Iustin Pop
  """Shows cluster information.
391 a8083063 Iustin Pop

392 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
393 469ee405 Iustin Pop
  @type args: list
394 469ee405 Iustin Pop
  @param args: should be an empty list
395 469ee405 Iustin Pop
  @rtype: int
396 469ee405 Iustin Pop
  @return: the desired exit code
397 469ee405 Iustin Pop

398 a8083063 Iustin Pop
  """
399 a2160e57 Iustin Pop
  cl = GetClient(query=True)
400 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
401 a8083063 Iustin Pop
402 c118d1f4 Michael Hanselmann
  if result["tags"]:
403 1f864b60 Iustin Pop
    tags = utils.CommaJoin(utils.NiceSort(result["tags"]))
404 c118d1f4 Michael Hanselmann
  else:
405 c118d1f4 Michael Hanselmann
    tags = "(none)"
406 5a3ab484 Iustin Pop
  if result["reserved_lvs"]:
407 5a3ab484 Iustin Pop
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
408 5a3ab484 Iustin Pop
  else:
409 5a3ab484 Iustin Pop
    reserved_lvs = "(none)"
410 be499e31 Agata Murawska
411 0e79564a Bernardo Dal Seno
  info = [
412 0e79564a Bernardo Dal Seno
    ("Cluster name", result["name"]),
413 0e79564a Bernardo Dal Seno
    ("Cluster UUID", result["uuid"]),
414 0e79564a Bernardo Dal Seno
415 0e79564a Bernardo Dal Seno
    ("Creation time", utils.FormatTime(result["ctime"])),
416 0e79564a Bernardo Dal Seno
    ("Modification time", utils.FormatTime(result["mtime"])),
417 0e79564a Bernardo Dal Seno
418 0e79564a Bernardo Dal Seno
    ("Master node", result["master"]),
419 0e79564a Bernardo Dal Seno
420 0e79564a Bernardo Dal Seno
    ("Architecture (this node)",
421 0e79564a Bernardo Dal Seno
     "%s (%s)" % (result["architecture"][0], result["architecture"][1])),
422 0e79564a Bernardo Dal Seno
423 0e79564a Bernardo Dal Seno
    ("Tags", tags),
424 0e79564a Bernardo Dal Seno
425 0e79564a Bernardo Dal Seno
    ("Default hypervisor", result["default_hypervisor"]),
426 0e79564a Bernardo Dal Seno
    ("Enabled hypervisors",
427 0e79564a Bernardo Dal Seno
     utils.CommaJoin(result["enabled_hypervisors"])),
428 0e79564a Bernardo Dal Seno
429 0e79564a Bernardo Dal Seno
    ("Hypervisor parameters", _FormatGroupedParams(result["hvparams"])),
430 0e79564a Bernardo Dal Seno
431 0e79564a Bernardo Dal Seno
    ("OS-specific hypervisor parameters",
432 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["os_hvp"])),
433 0e79564a Bernardo Dal Seno
434 0e79564a Bernardo Dal Seno
    ("OS parameters", _FormatGroupedParams(result["osparams"])),
435 0e79564a Bernardo Dal Seno
436 0e79564a Bernardo Dal Seno
    ("Hidden OSes", utils.CommaJoin(result["hidden_os"])),
437 0e79564a Bernardo Dal Seno
    ("Blacklisted OSes", utils.CommaJoin(result["blacklisted_os"])),
438 0e79564a Bernardo Dal Seno
439 0e79564a Bernardo Dal Seno
    ("Cluster parameters", [
440 0e79564a Bernardo Dal Seno
      ("candidate pool size",
441 0e79564a Bernardo Dal Seno
       compat.TryToRoman(result["candidate_pool_size"],
442 0e79564a Bernardo Dal Seno
                         convert=opts.roman_integers)),
443 0e79564a Bernardo Dal Seno
      ("master netdev", result["master_netdev"]),
444 0e79564a Bernardo Dal Seno
      ("master netmask", result["master_netmask"]),
445 0e79564a Bernardo Dal Seno
      ("use external master IP address setup script",
446 0e79564a Bernardo Dal Seno
       result["use_external_mip_script"]),
447 0e79564a Bernardo Dal Seno
      ("lvm volume group", result["volume_group_name"]),
448 0e79564a Bernardo Dal Seno
      ("lvm reserved volumes", reserved_lvs),
449 0e79564a Bernardo Dal Seno
      ("drbd usermode helper", result["drbd_usermode_helper"]),
450 0e79564a Bernardo Dal Seno
      ("file storage path", result["file_storage_dir"]),
451 0e79564a Bernardo Dal Seno
      ("shared file storage path", result["shared_file_storage_dir"]),
452 0e79564a Bernardo Dal Seno
      ("maintenance of node health", result["maintain_node_health"]),
453 0e79564a Bernardo Dal Seno
      ("uid pool", uidpool.FormatUidPool(result["uid_pool"])),
454 0e79564a Bernardo Dal Seno
      ("default instance allocator", result["default_iallocator"]),
455 0e79564a Bernardo Dal Seno
      ("primary ip version", result["primary_ip_version"]),
456 0e79564a Bernardo Dal Seno
      ("preallocation wipe disks", result["prealloc_wipe_disks"]),
457 0e79564a Bernardo Dal Seno
      ("OS search path", utils.CommaJoin(pathutils.OS_SEARCH_PATH)),
458 0e79564a Bernardo Dal Seno
      ("ExtStorage Providers search path",
459 0e79564a Bernardo Dal Seno
       utils.CommaJoin(pathutils.ES_SEARCH_PATH)),
460 0e79564a Bernardo Dal Seno
      ("enabled storage types",
461 0e79564a Bernardo Dal Seno
       utils.CommaJoin(result["enabled_storage_types"])),
462 966e1580 Helga Velroyen
      ("enabled disk templates",
463 966e1580 Helga Velroyen
       utils.CommaJoin(result["enabled_disk_templates"])),
464 0e79564a Bernardo Dal Seno
      ]),
465 0e79564a Bernardo Dal Seno
466 0e79564a Bernardo Dal Seno
    ("Default node parameters",
467 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["ndparams"], roman=opts.roman_integers)),
468 0e79564a Bernardo Dal Seno
469 0e79564a Bernardo Dal Seno
    ("Default instance parameters",
470 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["beparams"], roman=opts.roman_integers)),
471 0e79564a Bernardo Dal Seno
472 0e79564a Bernardo Dal Seno
    ("Default nic parameters",
473 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["nicparams"], roman=opts.roman_integers)),
474 0e79564a Bernardo Dal Seno
475 0e79564a Bernardo Dal Seno
    ("Default disk parameters",
476 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["diskparams"], roman=opts.roman_integers)),
477 0e79564a Bernardo Dal Seno
478 0e79564a Bernardo Dal Seno
    ("Instance policy - limits for instances",
479 d00884a2 Bernardo Dal Seno
     FormatPolicyInfo(result["ipolicy"], None, True)),
480 0e79564a Bernardo Dal Seno
    ]
481 0e79564a Bernardo Dal Seno
482 0e79564a Bernardo Dal Seno
  PrintGenericInfo(info)
483 a8083063 Iustin Pop
  return 0
484 a8083063 Iustin Pop
485 a8083063 Iustin Pop
486 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
487 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
488 a8083063 Iustin Pop

489 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
490 469ee405 Iustin Pop
  @type args: list
491 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
492 469ee405 Iustin Pop
      the file to be copied
493 469ee405 Iustin Pop
  @rtype: int
494 469ee405 Iustin Pop
  @return: the desired exit code
495 a8083063 Iustin Pop

496 a8083063 Iustin Pop
  """
497 b3989551 Iustin Pop
  filename = args[0]
498 b3989551 Iustin Pop
  if not os.path.exists(filename):
499 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
500 debac808 Iustin Pop
                               errors.ECODE_INVAL)
501 b3989551 Iustin Pop
502 56bece1f Iustin Pop
  cl = GetClient()
503 56bece1f Iustin Pop
504 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
505 56bece1f Iustin Pop
506 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
507 b6e88032 Michael Hanselmann
                           secondary_ips=opts.use_replication_network,
508 b6e88032 Michael Hanselmann
                           nodegroup=opts.nodegroup)
509 e00ea635 Michael Hanselmann
510 224ff0f7 Michael Hanselmann
  srun = ssh.SshRunner(cluster_name)
511 b3989551 Iustin Pop
  for node in results:
512 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
513 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
514 b3989551 Iustin Pop
515 a8083063 Iustin Pop
  return 0
516 a8083063 Iustin Pop
517 a8083063 Iustin Pop
518 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
519 a8083063 Iustin Pop
  """Run a command on some nodes.
520 a8083063 Iustin Pop

521 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
522 469ee405 Iustin Pop
  @type args: list
523 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
524 469ee405 Iustin Pop
  @rtype: int
525 469ee405 Iustin Pop
  @return: the desired exit code
526 a8083063 Iustin Pop

527 a8083063 Iustin Pop
  """
528 56bece1f Iustin Pop
  cl = GetClient()
529 7688d0d3 Michael Hanselmann
530 a8083063 Iustin Pop
  command = " ".join(args)
531 4040a784 Iustin Pop
532 b6e88032 Michael Hanselmann
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl, nodegroup=opts.nodegroup)
533 56bece1f Iustin Pop
534 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
535 56bece1f Iustin Pop
                                                    "master_node"])
536 b3989551 Iustin Pop
537 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
538 b3989551 Iustin Pop
539 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
540 b3989551 Iustin Pop
  if master_node in nodes:
541 b3989551 Iustin Pop
    nodes.remove(master_node)
542 b3989551 Iustin Pop
    nodes.append(master_node)
543 b3989551 Iustin Pop
544 b3989551 Iustin Pop
  for name in nodes:
545 052783ff Michael Hanselmann
    result = srun.Run(name, constants.SSH_LOGIN_USER, command)
546 d5b031dc Michael Hanselmann
547 d5b031dc Michael Hanselmann
    if opts.failure_only and result.exit_code == constants.EXIT_SUCCESS:
548 d5b031dc Michael Hanselmann
      # Do not output anything for successful commands
549 d5b031dc Michael Hanselmann
      continue
550 d5b031dc Michael Hanselmann
551 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
552 a24aed2a Michael Hanselmann
    if opts.show_machine_names:
553 a24aed2a Michael Hanselmann
      for line in result.output.splitlines():
554 a24aed2a Michael Hanselmann
        ToStdout("%s: %s", name, line)
555 a24aed2a Michael Hanselmann
    else:
556 a24aed2a Michael Hanselmann
      ToStdout("node: %s", name)
557 a24aed2a Michael Hanselmann
      ToStdout("%s", result.output)
558 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
559 b3989551 Iustin Pop
560 b3989551 Iustin Pop
  return 0
561 a8083063 Iustin Pop
562 a8083063 Iustin Pop
563 a8083063 Iustin Pop
def VerifyCluster(opts, args):
564 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
565 a8083063 Iustin Pop

566 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
567 469ee405 Iustin Pop
  @type args: list
568 469ee405 Iustin Pop
  @param args: should be an empty list
569 469ee405 Iustin Pop
  @rtype: int
570 469ee405 Iustin Pop
  @return: the desired exit code
571 a8083063 Iustin Pop

572 a8083063 Iustin Pop
  """
573 8d59409f Iustin Pop
  skip_checks = []
574 bf93ae69 Adeodato Simo
575 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
576 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
577 bf93ae69 Adeodato Simo
578 fcad7225 Michael Hanselmann
  cl = GetClient()
579 bf93ae69 Adeodato Simo
580 fcad7225 Michael Hanselmann
  op = opcodes.OpClusterVerify(verbose=opts.verbose,
581 fcad7225 Michael Hanselmann
                               error_codes=opts.error_codes,
582 fcad7225 Michael Hanselmann
                               debug_simulate_errors=opts.simulate_errors,
583 fcad7225 Michael Hanselmann
                               skip_checks=skip_checks,
584 93f2399e Andrea Spadaccini
                               ignore_errors=opts.ignore_errors,
585 fcad7225 Michael Hanselmann
                               group_name=opts.nodegroup)
586 fcad7225 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
587 bf93ae69 Adeodato Simo
588 fcad7225 Michael Hanselmann
  # Keep track of submitted jobs
589 fcad7225 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
590 fcad7225 Michael Hanselmann
591 fcad7225 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
592 fcad7225 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
593 bf93ae69 Adeodato Simo
594 fcad7225 Michael Hanselmann
  results = jex.GetResults()
595 ebe6cf38 Michael Hanselmann
596 ebe6cf38 Michael Hanselmann
  (bad_jobs, bad_results) = \
597 ebe6cf38 Michael Hanselmann
    map(len,
598 ebe6cf38 Michael Hanselmann
        # Convert iterators to lists
599 ebe6cf38 Michael Hanselmann
        map(list,
600 ebe6cf38 Michael Hanselmann
            # Count errors
601 ebe6cf38 Michael Hanselmann
            map(compat.partial(itertools.ifilterfalse, bool),
602 ebe6cf38 Michael Hanselmann
                # Convert result to booleans in a tuple
603 ebe6cf38 Michael Hanselmann
                zip(*((job_success, len(op_results) == 1 and op_results[0])
604 ebe6cf38 Michael Hanselmann
                      for (job_success, op_results) in results)))))
605 ebe6cf38 Michael Hanselmann
606 ebe6cf38 Michael Hanselmann
  if bad_jobs == 0 and bad_results == 0:
607 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
608 e0508c86 Guido Trotter
  else:
609 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
610 ebe6cf38 Michael Hanselmann
    if bad_jobs > 0:
611 ebe6cf38 Michael Hanselmann
      ToStdout("%s job(s) failed while verifying the cluster.", bad_jobs)
612 fcad7225 Michael Hanselmann
613 fcad7225 Michael Hanselmann
  return rcode
614 a8083063 Iustin Pop
615 a8083063 Iustin Pop
616 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
617 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
618 f4d4e184 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 f4d4e184 Iustin Pop

625 f4d4e184 Iustin Pop
  """
626 f1b083ce Michael Hanselmann
  cl = GetClient()
627 f1b083ce Michael Hanselmann
628 bd8210a7 Iustin Pop
  op = opcodes.OpClusterVerifyDisks()
629 f4d4e184 Iustin Pop
630 ae1a845c Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
631 ae1a845c Michael Hanselmann
632 ae1a845c Michael Hanselmann
  # Keep track of submitted jobs
633 ae1a845c Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
634 ae1a845c Michael Hanselmann
635 ae1a845c Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
636 ae1a845c Michael Hanselmann
    jex.AddJobId(None, status, job_id)
637 b63ed789 Iustin Pop
638 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
639 b63ed789 Iustin Pop
640 ae1a845c Michael Hanselmann
  for (status, result) in jex.GetResults():
641 ae1a845c Michael Hanselmann
    if not status:
642 ae1a845c Michael Hanselmann
      ToStdout("Job failed: %s", result)
643 ae1a845c Michael Hanselmann
      continue
644 ae1a845c Michael Hanselmann
645 ae1a845c Michael Hanselmann
    ((bad_nodes, instances, missing), ) = result
646 ae1a845c Michael Hanselmann
647 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
648 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
649 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
650 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
651 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
652 b63ed789 Iustin Pop
653 f4d4e184 Iustin Pop
    for iname in instances:
654 b63ed789 Iustin Pop
      if iname in missing:
655 b63ed789 Iustin Pop
        continue
656 83f5d475 Iustin Pop
      op = opcodes.OpInstanceActivateDisks(instance_name=iname)
657 f4d4e184 Iustin Pop
      try:
658 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
659 f1b083ce Michael Hanselmann
        SubmitOpCode(op, opts=opts, cl=cl)
660 f4d4e184 Iustin Pop
      except errors.GenericError, err:
661 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
662 f4d4e184 Iustin Pop
        retcode |= nret
663 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
664 b63ed789 Iustin Pop
665 ae1a845c Michael Hanselmann
    if missing:
666 ae1a845c Michael Hanselmann
      for iname, ival in missing.iteritems():
667 ae1a845c Michael Hanselmann
        all_missing = compat.all(x[0] in bad_nodes for x in ival)
668 ae1a845c Michael Hanselmann
        if all_missing:
669 ae1a845c Michael Hanselmann
          ToStdout("Instance %s cannot be verified as it lives on"
670 ae1a845c Michael Hanselmann
                   " broken nodes", iname)
671 ae1a845c Michael Hanselmann
        else:
672 ae1a845c Michael Hanselmann
          ToStdout("Instance %s has missing logical volumes:", iname)
673 ae1a845c Michael Hanselmann
          ival.sort()
674 ae1a845c Michael Hanselmann
          for node, vol in ival:
675 ae1a845c Michael Hanselmann
            if node in bad_nodes:
676 ae1a845c Michael Hanselmann
              ToStdout("\tbroken node %s /dev/%s", node, vol)
677 ae1a845c Michael Hanselmann
            else:
678 ae1a845c Michael Hanselmann
              ToStdout("\t%s /dev/%s", node, vol)
679 ae1a845c Michael Hanselmann
680 ae1a845c Michael Hanselmann
      ToStdout("You need to replace or recreate disks for all the above"
681 ae1a845c Michael Hanselmann
               " instances if this message persists after fixing broken nodes.")
682 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
683 9b99be28 Michael Hanselmann
    elif not instances:
684 9b99be28 Michael Hanselmann
      ToStdout("No disks need to be activated.")
685 f4d4e184 Iustin Pop
686 f4d4e184 Iustin Pop
  return retcode
687 f4d4e184 Iustin Pop
688 f4d4e184 Iustin Pop
689 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
690 60975797 Iustin Pop
  """Verify sizes of cluster disks.
691 60975797 Iustin Pop

692 60975797 Iustin Pop
  @param opts: the command line options selected by the user
693 60975797 Iustin Pop
  @type args: list
694 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
695 60975797 Iustin Pop
  @rtype: int
696 60975797 Iustin Pop
  @return: the desired exit code
697 60975797 Iustin Pop

698 60975797 Iustin Pop
  """
699 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
700 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
701 60975797 Iustin Pop
702 60975797 Iustin Pop
703 4331f6cd Michael Hanselmann
@UsesRPC
704 a8083063 Iustin Pop
def MasterFailover(opts, args):
705 a8083063 Iustin Pop
  """Failover the master node.
706 a8083063 Iustin Pop

707 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
708 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
709 a8083063 Iustin Pop
  master.
710 a8083063 Iustin Pop

711 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
712 469ee405 Iustin Pop
  @type args: list
713 469ee405 Iustin Pop
  @param args: should be an empty list
714 469ee405 Iustin Pop
  @rtype: int
715 469ee405 Iustin Pop
  @return: the desired exit code
716 469ee405 Iustin Pop

717 a8083063 Iustin Pop
  """
718 6022a419 Iustin Pop
  if opts.no_voting and not opts.yes_do_it:
719 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
720 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
721 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
722 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
723 8e2524c3 Guido Trotter
    if not AskUser(usertext):
724 8e2524c3 Guido Trotter
      return 1
725 8e2524c3 Guido Trotter
726 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
727 a8083063 Iustin Pop
728 a8083063 Iustin Pop
729 4404ffad Iustin Pop
def MasterPing(opts, args):
730 4404ffad Iustin Pop
  """Checks if the master is alive.
731 4404ffad Iustin Pop

732 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
733 4404ffad Iustin Pop
  @type args: list
734 4404ffad Iustin Pop
  @param args: should be an empty list
735 4404ffad Iustin Pop
  @rtype: int
736 4404ffad Iustin Pop
  @return: the desired exit code
737 4404ffad Iustin Pop

738 4404ffad Iustin Pop
  """
739 4404ffad Iustin Pop
  try:
740 4404ffad Iustin Pop
    cl = GetClient()
741 4404ffad Iustin Pop
    cl.QueryClusterInfo()
742 4404ffad Iustin Pop
    return 0
743 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
744 4404ffad Iustin Pop
    return 1
745 4404ffad Iustin Pop
746 4404ffad Iustin Pop
747 73415719 Iustin Pop
def SearchTags(opts, args):
748 73415719 Iustin Pop
  """Searches the tags on all the cluster.
749 73415719 Iustin Pop

750 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
751 469ee405 Iustin Pop
  @type args: list
752 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
753 469ee405 Iustin Pop
  @rtype: int
754 469ee405 Iustin Pop
  @return: the desired exit code
755 469ee405 Iustin Pop

756 73415719 Iustin Pop
  """
757 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
758 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
759 73415719 Iustin Pop
  if not result:
760 73415719 Iustin Pop
    return 1
761 73415719 Iustin Pop
  result = list(result)
762 73415719 Iustin Pop
  result.sort()
763 73415719 Iustin Pop
  for path, tag in result:
764 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
765 73415719 Iustin Pop
766 73415719 Iustin Pop
767 b6267745 Andrea Spadaccini
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
768 b6267745 Andrea Spadaccini
  """Reads and verifies an X509 certificate.
769 b6267745 Andrea Spadaccini

770 b6267745 Andrea Spadaccini
  @type cert_filename: string
771 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
772 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
773 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
774 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
775 b6267745 Andrea Spadaccini
                             the public certificate
776 b6267745 Andrea Spadaccini
  @rtype: string
777 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
778 b6267745 Andrea Spadaccini

779 b6267745 Andrea Spadaccini
  """
780 b6267745 Andrea Spadaccini
  try:
781 b6267745 Andrea Spadaccini
    pem = utils.ReadFile(cert_filename)
782 b6267745 Andrea Spadaccini
  except IOError, err:
783 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
784 b6267745 Andrea Spadaccini
                               "Unable to read certificate: %s" % str(err))
785 b6267745 Andrea Spadaccini
786 b6267745 Andrea Spadaccini
  try:
787 b6267745 Andrea Spadaccini
    OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
788 b6267745 Andrea Spadaccini
  except Exception, err:
789 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
790 b6267745 Andrea Spadaccini
                               "Unable to load certificate: %s" % str(err))
791 b6267745 Andrea Spadaccini
792 b6267745 Andrea Spadaccini
  if verify_private_key:
793 b6267745 Andrea Spadaccini
    try:
794 b6267745 Andrea Spadaccini
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, pem)
795 b6267745 Andrea Spadaccini
    except Exception, err:
796 b6267745 Andrea Spadaccini
      raise errors.X509CertError(cert_filename,
797 b6267745 Andrea Spadaccini
                                 "Unable to load private key: %s" % str(err))
798 b6267745 Andrea Spadaccini
799 b6267745 Andrea Spadaccini
  return pem
800 b6267745 Andrea Spadaccini
801 b6267745 Andrea Spadaccini
802 5ae4945a Iustin Pop
def _RenewCrypto(new_cluster_cert, new_rapi_cert, # pylint: disable=R0911
803 b6267745 Andrea Spadaccini
                 rapi_cert_filename, new_spice_cert, spice_cert_filename,
804 b6267745 Andrea Spadaccini
                 spice_cacert_filename, new_confd_hmac_key, new_cds,
805 b6267745 Andrea Spadaccini
                 cds_filename, force):
806 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
807 6d4a1656 Michael Hanselmann

808 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
809 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
810 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
811 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
812 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
813 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
814 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
815 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
816 b6267745 Andrea Spadaccini
  @type spice_cert_filename: string
817 b6267745 Andrea Spadaccini
  @param spice_cert_filename: Path to file containing new SPICE certificate
818 b6267745 Andrea Spadaccini
  @type spice_cacert_filename: string
819 b6267745 Andrea Spadaccini
  @param spice_cacert_filename: Path to file containing the certificate of the
820 b6267745 Andrea Spadaccini
                                CA that signed the SPICE certificate
821 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
822 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
823 3db3eb2a Michael Hanselmann
  @type new_cds: bool
824 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
825 3db3eb2a Michael Hanselmann
  @type cds_filename: string
826 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
827 6d4a1656 Michael Hanselmann
  @type force: bool
828 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
829 6d4a1656 Michael Hanselmann

830 6d4a1656 Michael Hanselmann
  """
831 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
832 6e060e15 Andrea Spadaccini
    ToStderr("Only one of the --new-rapi-certificate and --rapi-certificate"
833 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
834 6d4a1656 Michael Hanselmann
    return 1
835 6d4a1656 Michael Hanselmann
836 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
837 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
838 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
839 3db3eb2a Michael Hanselmann
             " the same time.")
840 3db3eb2a Michael Hanselmann
    return 1
841 3db3eb2a Michael Hanselmann
842 b6267745 Andrea Spadaccini
  if new_spice_cert and (spice_cert_filename or spice_cacert_filename):
843 b6267745 Andrea Spadaccini
    ToStderr("When using --new-spice-certificate, the --spice-certificate"
844 b6267745 Andrea Spadaccini
             " and --spice-ca-certificate must not be used.")
845 b6267745 Andrea Spadaccini
    return 1
846 6d4a1656 Michael Hanselmann
847 b6267745 Andrea Spadaccini
  if bool(spice_cacert_filename) ^ bool(spice_cert_filename):
848 b6267745 Andrea Spadaccini
    ToStderr("Both --spice-certificate and --spice-ca-certificate must be"
849 b6267745 Andrea Spadaccini
             " specified.")
850 b6267745 Andrea Spadaccini
    return 1
851 6d4a1656 Michael Hanselmann
852 b6267745 Andrea Spadaccini
  rapi_cert_pem, spice_cert_pem, spice_cacert_pem = (None, None, None)
853 b6267745 Andrea Spadaccini
  try:
854 b6267745 Andrea Spadaccini
    if rapi_cert_filename:
855 b6267745 Andrea Spadaccini
      rapi_cert_pem = _ReadAndVerifyCert(rapi_cert_filename, True)
856 b6267745 Andrea Spadaccini
    if spice_cert_filename:
857 b6267745 Andrea Spadaccini
      spice_cert_pem = _ReadAndVerifyCert(spice_cert_filename, True)
858 b6267745 Andrea Spadaccini
      spice_cacert_pem = _ReadAndVerifyCert(spice_cacert_filename)
859 b6267745 Andrea Spadaccini
  except errors.X509CertError, err:
860 b6267745 Andrea Spadaccini
    ToStderr("Unable to load X509 certificate from %s: %s", err[0], err[1])
861 b6267745 Andrea Spadaccini
    return 1
862 6d4a1656 Michael Hanselmann
863 3db3eb2a Michael Hanselmann
  if cds_filename:
864 3db3eb2a Michael Hanselmann
    try:
865 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
866 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
867 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
868 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
869 3db3eb2a Michael Hanselmann
      return 1
870 3db3eb2a Michael Hanselmann
  else:
871 3db3eb2a Michael Hanselmann
    cds = None
872 3db3eb2a Michael Hanselmann
873 6d4a1656 Michael Hanselmann
  if not force:
874 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
875 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
876 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
877 6d4a1656 Michael Hanselmann
      return 1
878 6d4a1656 Michael Hanselmann
879 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
880 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
881 b6267745 Andrea Spadaccini
    bootstrap.GenerateClusterCrypto(new_cluster_cert,
882 b6267745 Andrea Spadaccini
                                    new_rapi_cert,
883 b6267745 Andrea Spadaccini
                                    new_spice_cert,
884 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
885 3db3eb2a Michael Hanselmann
                                    new_cds,
886 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
887 b6267745 Andrea Spadaccini
                                    spice_cert_pem=spice_cert_pem,
888 b6267745 Andrea Spadaccini
                                    spice_cacert_pem=spice_cacert_pem,
889 3db3eb2a Michael Hanselmann
                                    cds=cds)
890 6d4a1656 Michael Hanselmann
891 6d4a1656 Michael Hanselmann
    files_to_copy = []
892 6d4a1656 Michael Hanselmann
893 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
894 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.NODED_CERT_FILE)
895 6d4a1656 Michael Hanselmann
896 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
897 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.RAPI_CERT_FILE)
898 6d4a1656 Michael Hanselmann
899 b6267745 Andrea Spadaccini
    if new_spice_cert or spice_cert_pem:
900 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.SPICE_CERT_FILE)
901 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.SPICE_CACERT_FILE)
902 b6267745 Andrea Spadaccini
903 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
904 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.CONFD_HMAC_KEY)
905 6d4a1656 Michael Hanselmann
906 3db3eb2a Michael Hanselmann
    if new_cds or cds:
907 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.CLUSTER_DOMAIN_SECRET_FILE)
908 3db3eb2a Michael Hanselmann
909 6d4a1656 Michael Hanselmann
    if files_to_copy:
910 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
911 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
912 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
913 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
914 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
915 6d4a1656 Michael Hanselmann
916 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
917 6d4a1656 Michael Hanselmann
918 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
919 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
920 6d4a1656 Michael Hanselmann
921 6d4a1656 Michael Hanselmann
  return 0
922 6d4a1656 Michael Hanselmann
923 6d4a1656 Michael Hanselmann
924 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
925 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
926 6d4a1656 Michael Hanselmann

927 6d4a1656 Michael Hanselmann
  """
928 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
929 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
930 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
931 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
932 b6267745 Andrea Spadaccini
                      opts.spice_cert,
933 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
934 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
935 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
936 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
937 6d4a1656 Michael Hanselmann
                      opts.force)
938 6d4a1656 Michael Hanselmann
939 6d4a1656 Michael Hanselmann
940 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
941 90b6aa3a Manuel Franceschini
  """Modify the cluster.
942 90b6aa3a Manuel Franceschini

943 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
944 469ee405 Iustin Pop
  @type args: list
945 469ee405 Iustin Pop
  @param args: should be an empty list
946 469ee405 Iustin Pop
  @rtype: int
947 469ee405 Iustin Pop
  @return: the desired exit code
948 90b6aa3a Manuel Franceschini

949 90b6aa3a Manuel Franceschini
  """
950 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
951 ed14ed48 Luca Bigliardi
          not opts.drbd_storage or opts.drbd_helper or
952 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
953 bc5d0215 Andrea Spadaccini
          opts.beparams or opts.nicparams or
954 bc5d0215 Andrea Spadaccini
          opts.ndparams or opts.diskparams or
955 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
956 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
957 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
958 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
959 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
960 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
961 b883637f René Nussbaumer
          opts.reserved_lvs is not None or
962 38f9d2cf Guido Trotter
          opts.master_netdev is not None or
963 5a8648eb Andrea Spadaccini
          opts.master_netmask is not None or
964 bf689b7a Andrea Spadaccini
          opts.use_external_mip_script is not None or
965 2da9f556 René Nussbaumer
          opts.prealloc_wipe_disks is not None or
966 2da9f556 René Nussbaumer
          opts.hv_state or
967 66af5ec5 Helga Velroyen
          # FIXME: Remove 'enabled_storage_types' once 'enabled_disk_templates'
968 66af5ec5 Helga Velroyen
          # are fully implemented.
969 c270ee07 Helga Velroyen
          opts.enabled_storage_types or
970 66af5ec5 Helga Velroyen
          opts.enabled_disk_templates or
971 e1a6850f Agata Murawska
          opts.disk_state or
972 1e7acc3b Iustin Pop
          opts.ispecs_mem_size or
973 1e7acc3b Iustin Pop
          opts.ispecs_cpu_count or
974 1e7acc3b Iustin Pop
          opts.ispecs_disk_count or
975 1e7acc3b Iustin Pop
          opts.ispecs_disk_size or
976 1e7acc3b Iustin Pop
          opts.ispecs_nic_count or
977 1e7acc3b Iustin Pop
          opts.ipolicy_disk_templates is not None or
978 31d827d1 René Nussbaumer
          opts.ipolicy_vcpu_ratio is not None or
979 31d827d1 René Nussbaumer
          opts.ipolicy_spindle_ratio is not None):
980 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
981 90b6aa3a Manuel Franceschini
    return 1
982 90b6aa3a Manuel Franceschini
983 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
984 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
985 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
986 90b6aa3a Manuel Franceschini
    return 1
987 6d4a1656 Michael Hanselmann
988 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
989 6d4a1656 Michael Hanselmann
    vg_name = ""
990 90b6aa3a Manuel Franceschini
991 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
992 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
993 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
994 ed14ed48 Luca Bigliardi
    return 1
995 ed14ed48 Luca Bigliardi
996 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage:
997 ed14ed48 Luca Bigliardi
    drbd_helper = ""
998 ed14ed48 Luca Bigliardi
999 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
1000 779c15bb Iustin Pop
  if hvlist is not None:
1001 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
1002 779c15bb Iustin Pop
1003 66af5ec5 Helga Velroyen
  # FIXME: Remove once 'enabled_disk_templates' are fully implemented.
1004 c270ee07 Helga Velroyen
  enabled_storage_types = opts.enabled_storage_types
1005 c270ee07 Helga Velroyen
  if enabled_storage_types is not None:
1006 c270ee07 Helga Velroyen
    enabled_storage_types = enabled_storage_types.split(",")
1007 c270ee07 Helga Velroyen
1008 66af5ec5 Helga Velroyen
  enabled_disk_templates = opts.enabled_disk_templates
1009 66af5ec5 Helga Velroyen
  if enabled_disk_templates:
1010 66af5ec5 Helga Velroyen
    enabled_disk_templates = enabled_disk_templates.split(",")
1011 66af5ec5 Helga Velroyen
1012 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
1013 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
1014 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
1015 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
1016 779c15bb Iustin Pop
1017 bc5d0215 Andrea Spadaccini
  diskparams = dict(opts.diskparams)
1018 bc5d0215 Andrea Spadaccini
1019 c20a19ed Iustin Pop
  for dt_params in diskparams.values():
1020 bc5d0215 Andrea Spadaccini
    utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
1021 bc5d0215 Andrea Spadaccini
1022 779c15bb Iustin Pop
  beparams = opts.beparams
1023 b2e233a5 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT)
1024 779c15bb Iustin Pop
1025 5af3da74 Guido Trotter
  nicparams = opts.nicparams
1026 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
1027 5af3da74 Guido Trotter
1028 6204ee71 René Nussbaumer
  ndparams = opts.ndparams
1029 6204ee71 René Nussbaumer
  if ndparams is not None:
1030 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
1031 1338f2b4 Balazs Lecz
1032 703fa9ab Iustin Pop
  ipolicy = CreateIPolicyFromOpts(
1033 976b78ba Iustin Pop
    ispecs_mem_size=opts.ispecs_mem_size,
1034 976b78ba Iustin Pop
    ispecs_cpu_count=opts.ispecs_cpu_count,
1035 976b78ba Iustin Pop
    ispecs_disk_count=opts.ispecs_disk_count,
1036 976b78ba Iustin Pop
    ispecs_disk_size=opts.ispecs_disk_size,
1037 976b78ba Iustin Pop
    ispecs_nic_count=opts.ispecs_nic_count,
1038 976b78ba Iustin Pop
    ipolicy_disk_templates=opts.ipolicy_disk_templates,
1039 976b78ba Iustin Pop
    ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio,
1040 31d827d1 René Nussbaumer
    ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio,
1041 976b78ba Iustin Pop
    )
1042 e1a6850f Agata Murawska
1043 3953242f Iustin Pop
  mnh = opts.maintain_node_health
1044 3953242f Iustin Pop
1045 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
1046 1338f2b4 Balazs Lecz
  if uid_pool is not None:
1047 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
1048 1338f2b4 Balazs Lecz
1049 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
1050 fdad8c4d Balazs Lecz
  if add_uids is not None:
1051 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
1052 fdad8c4d Balazs Lecz
1053 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
1054 fdad8c4d Balazs Lecz
  if remove_uids is not None:
1055 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
1056 fdad8c4d Balazs Lecz
1057 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
1058 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
1059 f38ea602 Iustin Pop
      opts.reserved_lvs = []
1060 f38ea602 Iustin Pop
    else:
1061 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
1062 f38ea602 Iustin Pop
1063 5a8648eb Andrea Spadaccini
  if opts.master_netmask is not None:
1064 5a8648eb Andrea Spadaccini
    try:
1065 5a8648eb Andrea Spadaccini
      opts.master_netmask = int(opts.master_netmask)
1066 5a8648eb Andrea Spadaccini
    except ValueError:
1067 5a8648eb Andrea Spadaccini
      ToStderr("The --master-netmask option expects an int parameter.")
1068 5a8648eb Andrea Spadaccini
      return 1
1069 5a8648eb Andrea Spadaccini
1070 bf689b7a Andrea Spadaccini
  ext_ip_script = opts.use_external_mip_script
1071 bf689b7a Andrea Spadaccini
1072 2da9f556 René Nussbaumer
  if opts.disk_state:
1073 2da9f556 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
1074 2da9f556 René Nussbaumer
  else:
1075 2da9f556 René Nussbaumer
    disk_state = {}
1076 2da9f556 René Nussbaumer
1077 2da9f556 René Nussbaumer
  hv_state = dict(opts.hv_state)
1078 2da9f556 René Nussbaumer
1079 c270ee07 Helga Velroyen
  op = opcodes.OpClusterSetParams(
1080 c270ee07 Helga Velroyen
    vg_name=vg_name,
1081 c270ee07 Helga Velroyen
    drbd_helper=drbd_helper,
1082 c270ee07 Helga Velroyen
    enabled_hypervisors=hvlist,
1083 c270ee07 Helga Velroyen
    hvparams=hvparams,
1084 c270ee07 Helga Velroyen
    os_hvp=None,
1085 c270ee07 Helga Velroyen
    beparams=beparams,
1086 c270ee07 Helga Velroyen
    nicparams=nicparams,
1087 c270ee07 Helga Velroyen
    ndparams=ndparams,
1088 c270ee07 Helga Velroyen
    diskparams=diskparams,
1089 c270ee07 Helga Velroyen
    ipolicy=ipolicy,
1090 c270ee07 Helga Velroyen
    candidate_pool_size=opts.candidate_pool_size,
1091 c270ee07 Helga Velroyen
    maintain_node_health=mnh,
1092 c270ee07 Helga Velroyen
    uid_pool=uid_pool,
1093 c270ee07 Helga Velroyen
    add_uids=add_uids,
1094 c270ee07 Helga Velroyen
    remove_uids=remove_uids,
1095 c270ee07 Helga Velroyen
    default_iallocator=opts.default_iallocator,
1096 c270ee07 Helga Velroyen
    prealloc_wipe_disks=opts.prealloc_wipe_disks,
1097 c270ee07 Helga Velroyen
    master_netdev=opts.master_netdev,
1098 c270ee07 Helga Velroyen
    master_netmask=opts.master_netmask,
1099 c270ee07 Helga Velroyen
    reserved_lvs=opts.reserved_lvs,
1100 c270ee07 Helga Velroyen
    use_external_mip_script=ext_ip_script,
1101 c270ee07 Helga Velroyen
    hv_state=hv_state,
1102 c270ee07 Helga Velroyen
    disk_state=disk_state,
1103 66af5ec5 Helga Velroyen
    # FIXME: remove once 'enabled_disk_templates' are fully implemented.
1104 c270ee07 Helga Velroyen
    enabled_storage_types=enabled_storage_types,
1105 66af5ec5 Helga Velroyen
    enabled_disk_templates=enabled_disk_templates,
1106 c270ee07 Helga Velroyen
    )
1107 745dae57 Michael Hanselmann
  SubmitOrSend(op, opts)
1108 90b6aa3a Manuel Franceschini
  return 0
1109 90b6aa3a Manuel Franceschini
1110 90b6aa3a Manuel Franceschini
1111 3ccafd0e Iustin Pop
def QueueOps(opts, args):
1112 3ccafd0e Iustin Pop
  """Queue operations.
1113 3ccafd0e Iustin Pop

1114 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1115 469ee405 Iustin Pop
  @type args: list
1116 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1117 469ee405 Iustin Pop
  @rtype: int
1118 469ee405 Iustin Pop
  @return: the desired exit code
1119 469ee405 Iustin Pop

1120 3ccafd0e Iustin Pop
  """
1121 3ccafd0e Iustin Pop
  command = args[0]
1122 3ccafd0e Iustin Pop
  client = GetClient()
1123 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
1124 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
1125 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
1126 3ccafd0e Iustin Pop
  elif command == "info":
1127 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
1128 3ccafd0e Iustin Pop
    if result[0]:
1129 3a24c527 Iustin Pop
      val = "set"
1130 3ccafd0e Iustin Pop
    else:
1131 3a24c527 Iustin Pop
      val = "unset"
1132 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
1133 2e668b38 Guido Trotter
  else:
1134 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1135 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1136 2e668b38 Guido Trotter
1137 3ccafd0e Iustin Pop
  return 0
1138 3ccafd0e Iustin Pop
1139 95b2e626 Michael Hanselmann
1140 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
1141 28b498cd Michael Hanselmann
  if until is None or until < time.time():
1142 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
1143 28b498cd Michael Hanselmann
  else:
1144 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
1145 28b498cd Michael Hanselmann
1146 28b498cd Michael Hanselmann
1147 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
1148 95b2e626 Michael Hanselmann
  """Watcher operations.
1149 95b2e626 Michael Hanselmann

1150 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1151 95b2e626 Michael Hanselmann
  @type args: list
1152 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1153 95b2e626 Michael Hanselmann
  @rtype: int
1154 95b2e626 Michael Hanselmann
  @return: the desired exit code
1155 95b2e626 Michael Hanselmann

1156 95b2e626 Michael Hanselmann
  """
1157 95b2e626 Michael Hanselmann
  command = args[0]
1158 95b2e626 Michael Hanselmann
  client = GetClient()
1159 95b2e626 Michael Hanselmann
1160 95b2e626 Michael Hanselmann
  if command == "continue":
1161 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
1162 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
1163 95b2e626 Michael Hanselmann
1164 95b2e626 Michael Hanselmann
  elif command == "pause":
1165 95b2e626 Michael Hanselmann
    if len(args) < 2:
1166 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
1167 95b2e626 Michael Hanselmann
1168 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
1169 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
1170 95b2e626 Michael Hanselmann
1171 95b2e626 Michael Hanselmann
  elif command == "info":
1172 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
1173 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
1174 95b2e626 Michael Hanselmann
1175 95b2e626 Michael Hanselmann
  else:
1176 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1177 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1178 95b2e626 Michael Hanselmann
1179 95b2e626 Michael Hanselmann
  return 0
1180 95b2e626 Michael Hanselmann
1181 95b2e626 Michael Hanselmann
1182 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
1183 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
1184 66d1f035 René Nussbaumer

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

1190 66d1f035 René Nussbaumer
  """
1191 66d1f035 René Nussbaumer
  if power:
1192 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
1193 66d1f035 René Nussbaumer
  else:
1194 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
1195 66d1f035 René Nussbaumer
1196 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
1197 66d1f035 René Nussbaumer
                            command=command,
1198 66d1f035 René Nussbaumer
                            ignore_status=True,
1199 cfed3b9f René Nussbaumer
                            timeout=opts.oob_timeout,
1200 cfed3b9f René Nussbaumer
                            power_delay=opts.power_delay)
1201 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
1202 66d1f035 René Nussbaumer
  errs = 0
1203 66d1f035 René Nussbaumer
  for node_result in result:
1204 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
1205 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
1206 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
1207 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
1208 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
1209 66d1f035 René Nussbaumer
      errs += 1
1210 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
1211 66d1f035 René Nussbaumer
               node_name)
1212 66d1f035 René Nussbaumer
1213 66d1f035 René Nussbaumer
  if errs > 0:
1214 66d1f035 René Nussbaumer
    return False
1215 66d1f035 René Nussbaumer
1216 66d1f035 René Nussbaumer
  return True
1217 66d1f035 René Nussbaumer
1218 66d1f035 René Nussbaumer
1219 3e0ed18c René Nussbaumer
def _InstanceStart(opts, inst_list, start, no_remember=False):
1220 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
1221 66d1f035 René Nussbaumer

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

1228 66d1f035 René Nussbaumer
  """
1229 66d1f035 René Nussbaumer
  if start:
1230 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
1231 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
1232 66d1f035 René Nussbaumer
  else:
1233 fcecea0b René Nussbaumer
    opcls = compat.partial(opcodes.OpInstanceShutdown,
1234 3e0ed18c René Nussbaumer
                           timeout=opts.shutdown_timeout,
1235 3e0ed18c René Nussbaumer
                           no_remember=no_remember)
1236 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
1237 66d1f035 René Nussbaumer
1238 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
1239 66d1f035 René Nussbaumer
1240 66d1f035 René Nussbaumer
  for inst in inst_list:
1241 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
1242 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
1243 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
1244 66d1f035 René Nussbaumer
1245 66d1f035 René Nussbaumer
  results = jex.GetResults()
1246 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
1247 66d1f035 René Nussbaumer
1248 66d1f035 René Nussbaumer
  if bad_cnt == 0:
1249 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
1250 66d1f035 René Nussbaumer
  else:
1251 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
1252 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
1253 66d1f035 René Nussbaumer
             len(results))
1254 66d1f035 René Nussbaumer
    return False
1255 66d1f035 René Nussbaumer
1256 66d1f035 René Nussbaumer
  return True
1257 66d1f035 René Nussbaumer
1258 66d1f035 René Nussbaumer
1259 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
1260 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
1261 66d1f035 René Nussbaumer

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

1264 66d1f035 René Nussbaumer
  """
1265 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1266 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1267 66d1f035 René Nussbaumer
    """Init the object.
1268 66d1f035 René Nussbaumer

1269 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1270 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1271 66d1f035 René Nussbaumer
    @type node2ip: dict
1272 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1273 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1274 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1275 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1276 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1277 66d1f035 René Nussbaumer

1278 66d1f035 René Nussbaumer
    """
1279 66d1f035 René Nussbaumer
    self.down = set(node_list)
1280 66d1f035 René Nussbaumer
    self.up = set()
1281 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1282 66d1f035 René Nussbaumer
    self.success = True
1283 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1284 66d1f035 René Nussbaumer
    self.port = port
1285 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1286 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1287 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1288 66d1f035 René Nussbaumer
1289 66d1f035 René Nussbaumer
  def __call__(self):
1290 66d1f035 René Nussbaumer
    """When called we run action_cb.
1291 66d1f035 René Nussbaumer

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

1294 66d1f035 René Nussbaumer
    """
1295 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1296 66d1f035 René Nussbaumer
      self.success = False
1297 66d1f035 René Nussbaumer
1298 66d1f035 René Nussbaumer
    if self.down:
1299 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1300 66d1f035 René Nussbaumer
    else:
1301 66d1f035 René Nussbaumer
      return self.success
1302 66d1f035 René Nussbaumer
1303 66d1f035 René Nussbaumer
  def Wait(self, secs):
1304 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1305 66d1f035 René Nussbaumer

1306 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1307 66d1f035 René Nussbaumer

1308 66d1f035 René Nussbaumer
    """
1309 66d1f035 René Nussbaumer
    start = time.time()
1310 66d1f035 René Nussbaumer
    for node in self.down:
1311 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1312 66d1f035 René Nussbaumer
                       live_port_needed=True):
1313 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1314 66d1f035 René Nussbaumer
        self.up.add(node)
1315 66d1f035 René Nussbaumer
        self.down -= self.up
1316 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1317 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1318 66d1f035 René Nussbaumer
        return
1319 66d1f035 René Nussbaumer
1320 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1321 66d1f035 René Nussbaumer
1322 66d1f035 René Nussbaumer
1323 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1324 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1325 66d1f035 René Nussbaumer

1326 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1327 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1328 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1329 66d1f035 René Nussbaumer

1330 66d1f035 René Nussbaumer
  """
1331 66d1f035 René Nussbaumer
  client = GetClient()
1332 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1333 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1334 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1335 66d1f035 René Nussbaumer
  else:
1336 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1337 66d1f035 René Nussbaumer
1338 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1339 66d1f035 René Nussbaumer
                 for node in node_list)
1340 66d1f035 René Nussbaumer
1341 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1342 8e74adce René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port,
1343 8e74adce René Nussbaumer
                                        ToStdout)
1344 66d1f035 René Nussbaumer
1345 66d1f035 René Nussbaumer
  try:
1346 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1347 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1348 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1349 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1350 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1351 66d1f035 René Nussbaumer
    return False
1352 66d1f035 René Nussbaumer
1353 66d1f035 René Nussbaumer
1354 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1355 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1356 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1357 66d1f035 René Nussbaumer

1358 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1359 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1360 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1361 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1362 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1363 66d1f035 René Nussbaumer

1364 66d1f035 René Nussbaumer
  """
1365 66d1f035 René Nussbaumer
  start_inst_list = []
1366 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1367 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1368 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1369 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1370 66d1f035 René Nussbaumer
1371 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1372 66d1f035 René Nussbaumer
    del inst_map[inst]
1373 66d1f035 René Nussbaumer
1374 66d1f035 René Nussbaumer
  if start_inst_list:
1375 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1376 66d1f035 René Nussbaumer
1377 66d1f035 René Nussbaumer
  return True
1378 66d1f035 René Nussbaumer
1379 66d1f035 René Nussbaumer
1380 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1381 66d1f035 René Nussbaumer
  """Does the actual power on.
1382 66d1f035 René Nussbaumer

1383 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1384 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1385 66d1f035 René Nussbaumer
                         OOB)
1386 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1387 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1388 66d1f035 René Nussbaumer
  @return: The desired exit status
1389 66d1f035 René Nussbaumer

1390 66d1f035 René Nussbaumer
  """
1391 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1392 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1393 66d1f035 René Nussbaumer
             " manually if needed")
1394 66d1f035 René Nussbaumer
1395 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1396 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1397 66d1f035 René Nussbaumer
1398 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1399 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1400 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1401 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1402 66d1f035 René Nussbaumer
1403 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1404 66d1f035 René Nussbaumer
1405 66d1f035 René Nussbaumer
1406 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1407 66d1f035 René Nussbaumer
  """Does the actual power off.
1408 66d1f035 René Nussbaumer

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

1414 66d1f035 René Nussbaumer
  """
1415 3e0ed18c René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False, no_remember=True):
1416 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1417 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1418 66d1f035 René Nussbaumer
1419 66d1f035 René Nussbaumer
  if not node_list:
1420 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1421 66d1f035 René Nussbaumer
1422 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1423 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1424 66d1f035 René Nussbaumer
  else:
1425 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1426 66d1f035 René Nussbaumer
1427 66d1f035 René Nussbaumer
1428 1ca7b773 Michael Hanselmann
def Epo(opts, args, cl=None, _on_fn=_EpoOn, _off_fn=_EpoOff,
1429 1ca7b773 Michael Hanselmann
        _confirm_fn=ConfirmOperation,
1430 1ca7b773 Michael Hanselmann
        _stdout_fn=ToStdout, _stderr_fn=ToStderr):
1431 66d1f035 René Nussbaumer
  """EPO operations.
1432 66d1f035 René Nussbaumer

1433 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1434 66d1f035 René Nussbaumer
  @type args: list
1435 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1436 66d1f035 René Nussbaumer
  @rtype: int
1437 66d1f035 René Nussbaumer
  @return: the desired exit code
1438 66d1f035 René Nussbaumer

1439 66d1f035 René Nussbaumer
  """
1440 66d1f035 René Nussbaumer
  if opts.groups and opts.show_all:
1441 1ca7b773 Michael Hanselmann
    _stderr_fn("Only one of --groups or --all are allowed")
1442 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1443 66d1f035 René Nussbaumer
  elif args and opts.show_all:
1444 1ca7b773 Michael Hanselmann
    _stderr_fn("Arguments in combination with --all are not allowed")
1445 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1446 66d1f035 René Nussbaumer
1447 1ca7b773 Michael Hanselmann
  if cl is None:
1448 1ca7b773 Michael Hanselmann
    cl = GetClient()
1449 66d1f035 René Nussbaumer
1450 66d1f035 René Nussbaumer
  if opts.groups:
1451 1ca7b773 Michael Hanselmann
    node_query_list = \
1452 1ca7b773 Michael Hanselmann
      itertools.chain(*cl.QueryGroups(args, ["node_list"], False))
1453 66d1f035 René Nussbaumer
  else:
1454 66d1f035 René Nussbaumer
    node_query_list = args
1455 66d1f035 René Nussbaumer
1456 1ca7b773 Michael Hanselmann
  result = cl.QueryNodes(node_query_list, ["name", "master", "pinst_list",
1457 1ca7b773 Michael Hanselmann
                                           "sinst_list", "powered", "offline"],
1458 1ca7b773 Michael Hanselmann
                         False)
1459 45a36f36 Michael Hanselmann
1460 45a36f36 Michael Hanselmann
  all_nodes = map(compat.fst, result)
1461 66d1f035 René Nussbaumer
  node_list = []
1462 66d1f035 René Nussbaumer
  inst_map = {}
1463 3008f56c Iustin Pop
  for (node, master, pinsts, sinsts, powered, offline) in result:
1464 66d1f035 René Nussbaumer
    if not offline:
1465 66d1f035 René Nussbaumer
      for inst in (pinsts + sinsts):
1466 66d1f035 René Nussbaumer
        if inst in inst_map:
1467 66d1f035 René Nussbaumer
          if not master:
1468 66d1f035 René Nussbaumer
            inst_map[inst].add(node)
1469 66d1f035 René Nussbaumer
        elif master:
1470 66d1f035 René Nussbaumer
          inst_map[inst] = set()
1471 66d1f035 René Nussbaumer
        else:
1472 66d1f035 René Nussbaumer
          inst_map[inst] = set([node])
1473 66d1f035 René Nussbaumer
1474 66d1f035 René Nussbaumer
    if master and opts.on:
1475 66d1f035 René Nussbaumer
      # We ignore the master for turning on the machines, in fact we are
1476 66d1f035 René Nussbaumer
      # already operating on the master at this point :)
1477 66d1f035 René Nussbaumer
      continue
1478 66d1f035 René Nussbaumer
    elif master and not opts.show_all:
1479 1ca7b773 Michael Hanselmann
      _stderr_fn("%s is the master node, please do a master-failover to another"
1480 1ca7b773 Michael Hanselmann
                 " node not affected by the EPO or use --all if you intend to"
1481 1ca7b773 Michael Hanselmann
                 " shutdown the whole cluster", node)
1482 66d1f035 René Nussbaumer
      return constants.EXIT_FAILURE
1483 66d1f035 René Nussbaumer
    elif powered is None:
1484 1ca7b773 Michael Hanselmann
      _stdout_fn("Node %s does not support out-of-band handling, it can not be"
1485 1ca7b773 Michael Hanselmann
                 " handled in a fully automated manner", node)
1486 66d1f035 René Nussbaumer
    elif powered == opts.on:
1487 1ca7b773 Michael Hanselmann
      _stdout_fn("Node %s is already in desired power state, skipping", node)
1488 66d1f035 René Nussbaumer
    elif not offline or (offline and powered):
1489 66d1f035 René Nussbaumer
      node_list.append(node)
1490 66d1f035 René Nussbaumer
1491 1ca7b773 Michael Hanselmann
  if not (opts.force or _confirm_fn(all_nodes, "nodes", "epo")):
1492 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1493 66d1f035 René Nussbaumer
1494 66d1f035 René Nussbaumer
  if opts.on:
1495 1ca7b773 Michael Hanselmann
    return _on_fn(opts, all_nodes, node_list, inst_map)
1496 66d1f035 René Nussbaumer
  else:
1497 1ca7b773 Michael Hanselmann
    return _off_fn(opts, node_list, inst_map)
1498 1ca7b773 Michael Hanselmann
1499 66d1f035 René Nussbaumer
1500 a8083063 Iustin Pop
commands = {
1501 d0c8c01d Iustin Pop
  "init": (
1502 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
1503 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
1504 5a8648eb Andrea Spadaccini
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, MASTER_NETMASK_OPT,
1505 5a8648eb Andrea Spadaccini
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT,
1506 5a8648eb Andrea Spadaccini
     NOMODIFY_SSH_SETUP_OPT, SECONDARY_IP_OPT, VG_NAME_OPT,
1507 5a8648eb Andrea Spadaccini
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
1508 6204ee71 René Nussbaumer
     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
1509 bc5d0215 Andrea Spadaccini
     NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT, USE_EXTERNAL_MIP_SCRIPT,
1510 c074a9e8 Helga Velroyen
     DISK_PARAMS_OPT, HV_STATE_OPT, DISK_STATE_OPT, ENABLED_STORAGE_TYPES_OPT]
1511 c074a9e8 Helga Velroyen
     + INSTANCE_POLICY_OPTS,
1512 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
1513 d0c8c01d Iustin Pop
  "destroy": (
1514 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
1515 6ea815cf Iustin Pop
    "", "Destroy cluster"),
1516 d0c8c01d Iustin Pop
  "rename": (
1517 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
1518 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
1519 6ea815cf Iustin Pop
    "<new_name>",
1520 6ea815cf Iustin Pop
    "Renames the cluster"),
1521 d0c8c01d Iustin Pop
  "redist-conf": (
1522 aa06f8c6 Michael Hanselmann
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1523 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
1524 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
1525 d0c8c01d Iustin Pop
  "verify": (
1526 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
1527 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
1528 93f2399e Andrea Spadaccini
     DRY_RUN_OPT, PRIORITY_OPT, NODEGROUP_OPT, IGNORE_ERRORS_OPT],
1529 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
1530 d0c8c01d Iustin Pop
  "verify-disks": (
1531 aa06f8c6 Michael Hanselmann
    VerifyDisks, ARGS_NONE, [PRIORITY_OPT],
1532 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
1533 d0c8c01d Iustin Pop
  "repair-disk-sizes": (
1534 aa06f8c6 Michael Hanselmann
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
1535 eb5ac108 Michael Hanselmann
    "[instance...]", "Updates mismatches in recorded disk sizes"),
1536 d0c8c01d Iustin Pop
  "master-failover": (
1537 6022a419 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT, FORCE_FAILOVER],
1538 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
1539 d0c8c01d Iustin Pop
  "master-ping": (
1540 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
1541 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
1542 d0c8c01d Iustin Pop
  "version": (
1543 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
1544 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
1545 d0c8c01d Iustin Pop
  "getmaster": (
1546 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
1547 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
1548 d0c8c01d Iustin Pop
  "copyfile": (
1549 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
1550 b6e88032 Michael Hanselmann
    [NODE_LIST_OPT, USE_REPL_NET_OPT, NODEGROUP_OPT],
1551 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
1552 d0c8c01d Iustin Pop
  "command": (
1553 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
1554 d5b031dc Michael Hanselmann
    [NODE_LIST_OPT, NODEGROUP_OPT, SHOW_MACHINE_OPT, FAILURE_ONLY_OPT],
1555 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
1556 d0c8c01d Iustin Pop
  "info": (
1557 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
1558 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
1559 d0c8c01d Iustin Pop
  "list-tags": (
1560 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
1561 d0c8c01d Iustin Pop
  "add-tags": (
1562 6bc3ed14 Michael Hanselmann
    AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1563 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
1564 d0c8c01d Iustin Pop
  "remove-tags": (
1565 6bc3ed14 Michael Hanselmann
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1566 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
1567 d0c8c01d Iustin Pop
  "search-tags": (
1568 aa06f8c6 Michael Hanselmann
    SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "",
1569 aa06f8c6 Michael Hanselmann
    "Searches the tags on all objects on"
1570 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
1571 d0c8c01d Iustin Pop
  "queue": (
1572 6ea815cf Iustin Pop
    QueueOps,
1573 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
1574 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
1575 d0c8c01d Iustin Pop
  "watcher": (
1576 6ea815cf Iustin Pop
    WatcherOps,
1577 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
1578 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
1579 064c21f8 Iustin Pop
    [],
1580 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
1581 d0c8c01d Iustin Pop
  "modify": (
1582 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
1583 38f9d2cf Guido Trotter
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
1584 5a8648eb Andrea Spadaccini
     MASTER_NETMASK_OPT, NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT,
1585 5a8648eb Andrea Spadaccini
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT,
1586 5a8648eb Andrea Spadaccini
     DRBD_HELPER_OPT, NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT,
1587 5a8648eb Andrea Spadaccini
     RESERVED_LVS_OPT, DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT,
1588 2da9f556 René Nussbaumer
     NODE_PARAMS_OPT, USE_EXTERNAL_MIP_SCRIPT, DISK_PARAMS_OPT, HV_STATE_OPT,
1589 66af5ec5 Helga Velroyen
     DISK_STATE_OPT, SUBMIT_OPT, ENABLED_STORAGE_TYPES_OPT,
1590 66af5ec5 Helga Velroyen
     ENABLED_DISK_TEMPLATES_OPT] +
1591 32017174 Agata Murawska
    INSTANCE_POLICY_OPTS,
1592 6ea815cf Iustin Pop
    "[opts...]",
1593 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
1594 6d4a1656 Michael Hanselmann
  "renew-crypto": (
1595 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
1596 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
1597 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
1598 b6267745 Andrea Spadaccini
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT,
1599 b6267745 Andrea Spadaccini
     NEW_SPICE_CERT_OPT, SPICE_CERT_OPT, SPICE_CACERT_OPT],
1600 6d4a1656 Michael Hanselmann
    "[opts...]",
1601 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
1602 66d1f035 René Nussbaumer
  "epo": (
1603 66d1f035 René Nussbaumer
    Epo, [ArgUnknown()],
1604 fcecea0b René Nussbaumer
    [FORCE_OPT, ON_OPT, GROUPS_OPT, ALL_OPT, OOB_TIMEOUT_OPT,
1605 cfed3b9f René Nussbaumer
     SHUTDOWN_TIMEOUT_OPT, POWER_DELAY_OPT],
1606 66d1f035 René Nussbaumer
    "[opts...] [args]",
1607 66d1f035 René Nussbaumer
    "Performs an emergency power-off on given args"),
1608 fb926117 Andrea Spadaccini
  "activate-master-ip": (
1609 fb926117 Andrea Spadaccini
    ActivateMasterIp, ARGS_NONE, [], "", "Activates the master IP"),
1610 fb926117 Andrea Spadaccini
  "deactivate-master-ip": (
1611 fb926117 Andrea Spadaccini
    DeactivateMasterIp, ARGS_NONE, [CONFIRM_OPT], "",
1612 fb926117 Andrea Spadaccini
    "Deactivates the master IP"),
1613 a8083063 Iustin Pop
  }
1614 a8083063 Iustin Pop
1615 6d4a1656 Michael Hanselmann
1616 c28502b1 Iustin Pop
#: dictionary with aliases for commands
1617 c28502b1 Iustin Pop
aliases = {
1618 d0c8c01d Iustin Pop
  "masterfailover": "master-failover",
1619 96897af7 Alexander Schreiber
  "show": "info",
1620 c28502b1 Iustin Pop
}
1621 c28502b1 Iustin Pop
1622 c28502b1 Iustin Pop
1623 7b3e7d41 Michael Hanselmann
def Main():
1624 7b3e7d41 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
1625 7b3e7d41 Michael Hanselmann
                     aliases=aliases)