Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 81e3ab4f

History | View | Annotate | Download (50.9 kB)

1 7b3e7d41 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 afc3c260 Iustin Pop
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 7260cfbe Iustin Pop
"""Cluster related commands"""
22 a8083063 Iustin Pop
23 b459a848 Andrea Spadaccini
# pylint: disable=W0401,W0613,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2d54e29c Iustin Pop
# W0613: Unused argument, since all functions follow the same API
26 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
27 7260cfbe Iustin Pop
# C0103: Invalid name gnt-cluster
28 2f79bd34 Iustin Pop
29 b3989551 Iustin Pop
import os.path
30 95b2e626 Michael Hanselmann
import time
31 6d4a1656 Michael Hanselmann
import OpenSSL
32 66d1f035 René Nussbaumer
import itertools
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti.cli import *
35 a8083063 Iustin Pop
from ganeti import opcodes
36 c2a62a33 Michael Hanselmann
from ganeti import constants
37 f4d4e184 Iustin Pop
from ganeti import errors
38 b63ed789 Iustin Pop
from ganeti import utils
39 a0c9f010 Michael Hanselmann
from ganeti import bootstrap
40 b3989551 Iustin Pop
from ganeti import ssh
41 d3cfe525 Guido Trotter
from ganeti import objects
42 1338f2b4 Balazs Lecz
from ganeti import uidpool
43 cea881e5 Michael Hanselmann
from ganeti import compat
44 66d1f035 René Nussbaumer
from ganeti import netutils
45 66d1f035 René Nussbaumer
46 66d1f035 René Nussbaumer
47 66d1f035 René Nussbaumer
ON_OPT = cli_option("--on", default=False,
48 66d1f035 René Nussbaumer
                    action="store_true", dest="on",
49 66d1f035 René Nussbaumer
                    help="Recover from an EPO")
50 66d1f035 René Nussbaumer
51 66d1f035 René Nussbaumer
GROUPS_OPT = cli_option("--groups", default=False,
52 66d1f035 René Nussbaumer
                    action="store_true", dest="groups",
53 66d1f035 René Nussbaumer
                    help="Arguments are node groups instead of nodes")
54 66d1f035 René Nussbaumer
55 66d1f035 René Nussbaumer
_EPO_PING_INTERVAL = 30 # 30 seconds between pings
56 66d1f035 René Nussbaumer
_EPO_PING_TIMEOUT = 1 # 1 second
57 66d1f035 René Nussbaumer
_EPO_REACHABLE_TIMEOUT = 15 * 60 # 15 minutes
58 a8083063 Iustin Pop
59 a8083063 Iustin Pop
60 4331f6cd Michael Hanselmann
@UsesRPC
61 a8083063 Iustin Pop
def InitCluster(opts, args):
62 a8083063 Iustin Pop
  """Initialize the cluster.
63 a8083063 Iustin Pop

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

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

218 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
219 469ee405 Iustin Pop
  @type args: list
220 469ee405 Iustin Pop
  @param args: should be an empty list
221 469ee405 Iustin Pop
  @rtype: int
222 469ee405 Iustin Pop
  @return: the desired exit code
223 098c0958 Michael Hanselmann

224 a8083063 Iustin Pop
  """
225 a8083063 Iustin Pop
  if not opts.yes_do_it:
226 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
227 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
228 a8083063 Iustin Pop
    return 1
229 a8083063 Iustin Pop
230 c6d43e9e Iustin Pop
  op = opcodes.OpClusterDestroy()
231 400ca2f7 Iustin Pop
  master = SubmitOpCode(op, opts=opts)
232 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
233 140aa4a8 Iustin Pop
  # shutdown all the daemons
234 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
235 a8083063 Iustin Pop
  return 0
236 a8083063 Iustin Pop
237 a8083063 Iustin Pop
238 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
239 07bd8a51 Iustin Pop
  """Rename the cluster.
240 07bd8a51 Iustin Pop

241 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
242 469ee405 Iustin Pop
  @type args: list
243 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
244 469ee405 Iustin Pop
  @rtype: int
245 469ee405 Iustin Pop
  @return: the desired exit code
246 07bd8a51 Iustin Pop

247 07bd8a51 Iustin Pop
  """
248 6a016df9 Michael Hanselmann
  cl = GetClient()
249 6a016df9 Michael Hanselmann
250 6a016df9 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
251 6a016df9 Michael Hanselmann
252 6a016df9 Michael Hanselmann
  new_name = args[0]
253 07bd8a51 Iustin Pop
  if not opts.force:
254 6a016df9 Michael Hanselmann
    usertext = ("This will rename the cluster from '%s' to '%s'. If you are"
255 6a016df9 Michael Hanselmann
                " connected over the network to the cluster name, the"
256 6a016df9 Michael Hanselmann
                " operation is very dangerous as the IP address will be"
257 6a016df9 Michael Hanselmann
                " removed from the node and the change may not go through."
258 6a016df9 Michael Hanselmann
                " Continue?") % (cluster_name, new_name)
259 47988778 Iustin Pop
    if not AskUser(usertext):
260 07bd8a51 Iustin Pop
      return 1
261 07bd8a51 Iustin Pop
262 e126df25 Iustin Pop
  op = opcodes.OpClusterRename(name=new_name)
263 6a016df9 Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
264 6a016df9 Michael Hanselmann
265 48418fea Iustin Pop
  if result:
266 48418fea Iustin Pop
    ToStdout("Cluster renamed from '%s' to '%s'", cluster_name, result)
267 6a016df9 Michael Hanselmann
268 07bd8a51 Iustin Pop
  return 0
269 07bd8a51 Iustin Pop
270 07bd8a51 Iustin Pop
271 fb926117 Andrea Spadaccini
def ActivateMasterIp(opts, args):
272 fb926117 Andrea Spadaccini
  """Activates the master IP.
273 fb926117 Andrea Spadaccini

274 fb926117 Andrea Spadaccini
  """
275 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
276 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
277 fb926117 Andrea Spadaccini
  return 0
278 fb926117 Andrea Spadaccini
279 fb926117 Andrea Spadaccini
280 fb926117 Andrea Spadaccini
def DeactivateMasterIp(opts, args):
281 fb926117 Andrea Spadaccini
  """Deactivates the master IP.
282 fb926117 Andrea Spadaccini

283 fb926117 Andrea Spadaccini
  """
284 fb926117 Andrea Spadaccini
  if not opts.confirm:
285 fb926117 Andrea Spadaccini
    usertext = ("This will disable the master IP. All the open connections to"
286 fb926117 Andrea Spadaccini
                " the master IP will be closed. To reach the master you will"
287 fb926117 Andrea Spadaccini
                " need to use its node IP."
288 fb926117 Andrea Spadaccini
                " Continue?")
289 fb926117 Andrea Spadaccini
    if not AskUser(usertext):
290 fb926117 Andrea Spadaccini
      return 1
291 fb926117 Andrea Spadaccini
292 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterDeactivateMasterIp()
293 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
294 fb926117 Andrea Spadaccini
  return 0
295 fb926117 Andrea Spadaccini
296 fb926117 Andrea Spadaccini
297 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
298 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
299 afee0879 Iustin Pop

300 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
301 afee0879 Iustin Pop
  @type args: list
302 afee0879 Iustin Pop
  @param args: empty list
303 afee0879 Iustin Pop
  @rtype: int
304 afee0879 Iustin Pop
  @return: the desired exit code
305 afee0879 Iustin Pop

306 afee0879 Iustin Pop
  """
307 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
308 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
309 afee0879 Iustin Pop
  return 0
310 afee0879 Iustin Pop
311 afee0879 Iustin Pop
312 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
313 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
314 a8083063 Iustin Pop

315 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
316 469ee405 Iustin Pop
  @type args: list
317 469ee405 Iustin Pop
  @param args: should be an empty list
318 469ee405 Iustin Pop
  @rtype: int
319 469ee405 Iustin Pop
  @return: the desired exit code
320 a8083063 Iustin Pop

321 a8083063 Iustin Pop
  """
322 2e7b8369 Iustin Pop
  cl = GetClient()
323 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
324 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
325 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
326 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
327 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
328 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
329 a8083063 Iustin Pop
  return 0
330 a8083063 Iustin Pop
331 a8083063 Iustin Pop
332 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
333 a8083063 Iustin Pop
  """Write name of master node to the standard output.
334 a8083063 Iustin Pop

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

341 a8083063 Iustin Pop
  """
342 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
343 8eb148ae Iustin Pop
  ToStdout(master)
344 a8083063 Iustin Pop
  return 0
345 a8083063 Iustin Pop
346 cac599f1 Michael Hanselmann
347 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
348 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
349 1094acda Guido Trotter

350 1094acda Guido Trotter
  @type paramsdict: dict of dicts
351 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
352 664a9d73 René Nussbaumer
  @type level: int
353 664a9d73 René Nussbaumer
  @param level: Level of indention
354 1094acda Guido Trotter

355 1094acda Guido Trotter
  """
356 664a9d73 René Nussbaumer
  indent = "  " * level
357 9d91c6ab Guido Trotter
  for item, val in sorted(paramsdict.items()):
358 664a9d73 René Nussbaumer
    if isinstance(val, dict):
359 664a9d73 René Nussbaumer
      ToStdout("%s- %s:", indent, item)
360 d729e03a Guido Trotter
      _PrintGroupedParams(val, level=level + 1, roman=roman)
361 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
362 d729e03a Guido Trotter
      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
363 664a9d73 René Nussbaumer
    else:
364 664a9d73 René Nussbaumer
      ToStdout("%s  %s: %s", indent, item, val)
365 a8083063 Iustin Pop
366 cac599f1 Michael Hanselmann
367 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
368 a8083063 Iustin Pop
  """Shows cluster information.
369 a8083063 Iustin Pop

370 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
371 469ee405 Iustin Pop
  @type args: list
372 469ee405 Iustin Pop
  @param args: should be an empty list
373 469ee405 Iustin Pop
  @rtype: int
374 469ee405 Iustin Pop
  @return: the desired exit code
375 469ee405 Iustin Pop

376 a8083063 Iustin Pop
  """
377 2e7b8369 Iustin Pop
  cl = GetClient()
378 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
379 a8083063 Iustin Pop
380 3a24c527 Iustin Pop
  ToStdout("Cluster name: %s", result["name"])
381 259578eb Iustin Pop
  ToStdout("Cluster UUID: %s", result["uuid"])
382 a8083063 Iustin Pop
383 90f72445 Iustin Pop
  ToStdout("Creation time: %s", utils.FormatTime(result["ctime"]))
384 90f72445 Iustin Pop
  ToStdout("Modification time: %s", utils.FormatTime(result["mtime"]))
385 90f72445 Iustin Pop
386 3a24c527 Iustin Pop
  ToStdout("Master node: %s", result["master"])
387 a8083063 Iustin Pop
388 3a24c527 Iustin Pop
  ToStdout("Architecture (this node): %s (%s)",
389 3a24c527 Iustin Pop
           result["architecture"][0], result["architecture"][1])
390 a8083063 Iustin Pop
391 c118d1f4 Michael Hanselmann
  if result["tags"]:
392 1f864b60 Iustin Pop
    tags = utils.CommaJoin(utils.NiceSort(result["tags"]))
393 c118d1f4 Michael Hanselmann
  else:
394 c118d1f4 Michael Hanselmann
    tags = "(none)"
395 c118d1f4 Michael Hanselmann
396 c118d1f4 Michael Hanselmann
  ToStdout("Tags: %s", tags)
397 c118d1f4 Michael Hanselmann
398 02691904 Alexander Schreiber
  ToStdout("Default hypervisor: %s", result["default_hypervisor"])
399 1f864b60 Iustin Pop
  ToStdout("Enabled hypervisors: %s",
400 1f864b60 Iustin Pop
           utils.CommaJoin(result["enabled_hypervisors"]))
401 469f88e1 Iustin Pop
402 3a24c527 Iustin Pop
  ToStdout("Hypervisor parameters:")
403 1094acda Guido Trotter
  _PrintGroupedParams(result["hvparams"])
404 469f88e1 Iustin Pop
405 dbb24ec7 Iustin Pop
  ToStdout("OS-specific hypervisor parameters:")
406 664a9d73 René Nussbaumer
  _PrintGroupedParams(result["os_hvp"])
407 664a9d73 René Nussbaumer
408 dbb24ec7 Iustin Pop
  ToStdout("OS parameters:")
409 dbb24ec7 Iustin Pop
  _PrintGroupedParams(result["osparams"])
410 dbb24ec7 Iustin Pop
411 afc3c260 Iustin Pop
  ToStdout("Hidden OSes: %s", utils.CommaJoin(result["hidden_os"]))
412 afc3c260 Iustin Pop
  ToStdout("Blacklisted OSes: %s", utils.CommaJoin(result["blacklisted_os"]))
413 afc3c260 Iustin Pop
414 3a24c527 Iustin Pop
  ToStdout("Cluster parameters:")
415 d729e03a Guido Trotter
  ToStdout("  - candidate pool size: %s",
416 d729e03a Guido Trotter
            compat.TryToRoman(result["candidate_pool_size"],
417 d729e03a Guido Trotter
                              convert=opts.roman_integers))
418 a8001106 Guido Trotter
  ToStdout("  - master netdev: %s", result["master_netdev"])
419 5a8648eb Andrea Spadaccini
  ToStdout("  - master netmask: %s", result["master_netmask"])
420 bf689b7a Andrea Spadaccini
  ToStdout("  - use external master IP address setup script: %s",
421 bf689b7a Andrea Spadaccini
           result["use_external_mip_script"])
422 a8001106 Guido Trotter
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
423 5a3ab484 Iustin Pop
  if result["reserved_lvs"]:
424 5a3ab484 Iustin Pop
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
425 5a3ab484 Iustin Pop
  else:
426 5a3ab484 Iustin Pop
    reserved_lvs = "(none)"
427 5a3ab484 Iustin Pop
  ToStdout("  - lvm reserved volumes: %s", reserved_lvs)
428 ed14ed48 Luca Bigliardi
  ToStdout("  - drbd usermode helper: %s", result["drbd_usermode_helper"])
429 a8001106 Guido Trotter
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
430 4b97f902 Apollon Oikonomopoulos
  ToStdout("  - shared file storage path: %s",
431 4b97f902 Apollon Oikonomopoulos
           result["shared_file_storage_dir"])
432 3953242f Iustin Pop
  ToStdout("  - maintenance of node health: %s",
433 3953242f Iustin Pop
           result["maintain_node_health"])
434 d729e03a Guido Trotter
  ToStdout("  - uid pool: %s",
435 d729e03a Guido Trotter
            uidpool.FormatUidPool(result["uid_pool"],
436 d729e03a Guido Trotter
                                  roman=opts.roman_integers))
437 bf4af505 Apollon Oikonomopoulos
  ToStdout("  - default instance allocator: %s", result["default_iallocator"])
438 e7323b5e Manuel Franceschini
  ToStdout("  - primary ip version: %d", result["primary_ip_version"])
439 b18ecea2 René Nussbaumer
  ToStdout("  - preallocation wipe disks: %s", result["prealloc_wipe_disks"])
440 f36c3e2d Ben Lipton
  ToStdout("  - OS search path: %s", utils.CommaJoin(constants.OS_SEARCH_PATH))
441 4b7735f9 Iustin Pop
442 88be69ee René Nussbaumer
  ToStdout("Default node parameters:")
443 88be69ee René Nussbaumer
  _PrintGroupedParams(result["ndparams"], roman=opts.roman_integers)
444 88be69ee René Nussbaumer
445 4b7735f9 Iustin Pop
  ToStdout("Default instance parameters:")
446 d729e03a Guido Trotter
  _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
447 1094acda Guido Trotter
448 1094acda Guido Trotter
  ToStdout("Default nic parameters:")
449 d729e03a Guido Trotter
  _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers)
450 8a12ce45 Iustin Pop
451 be499e31 Agata Murawska
  ToStdout("Instance policy - limits for instances:")
452 be499e31 Agata Murawska
  for key in constants.IPOLICY_PARAMETERS:
453 be499e31 Agata Murawska
    ToStdout("  - %s", key)
454 be499e31 Agata Murawska
    _PrintGroupedParams(result["ipolicy"][key], roman=opts.roman_integers)
455 be499e31 Agata Murawska
456 a8083063 Iustin Pop
  return 0
457 a8083063 Iustin Pop
458 a8083063 Iustin Pop
459 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
460 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
461 a8083063 Iustin Pop

462 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
463 469ee405 Iustin Pop
  @type args: list
464 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
465 469ee405 Iustin Pop
      the file to be copied
466 469ee405 Iustin Pop
  @rtype: int
467 469ee405 Iustin Pop
  @return: the desired exit code
468 a8083063 Iustin Pop

469 a8083063 Iustin Pop
  """
470 b3989551 Iustin Pop
  filename = args[0]
471 b3989551 Iustin Pop
  if not os.path.exists(filename):
472 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
473 debac808 Iustin Pop
                               errors.ECODE_INVAL)
474 b3989551 Iustin Pop
475 56bece1f Iustin Pop
  cl = GetClient()
476 56bece1f Iustin Pop
477 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
478 56bece1f Iustin Pop
479 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
480 b6e88032 Michael Hanselmann
                           secondary_ips=opts.use_replication_network,
481 b6e88032 Michael Hanselmann
                           nodegroup=opts.nodegroup)
482 e00ea635 Michael Hanselmann
483 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
484 b3989551 Iustin Pop
  for node in results:
485 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
486 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
487 b3989551 Iustin Pop
488 a8083063 Iustin Pop
  return 0
489 a8083063 Iustin Pop
490 a8083063 Iustin Pop
491 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
492 a8083063 Iustin Pop
  """Run a command on some nodes.
493 a8083063 Iustin Pop

494 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
495 469ee405 Iustin Pop
  @type args: list
496 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
497 469ee405 Iustin Pop
  @rtype: int
498 469ee405 Iustin Pop
  @return: the desired exit code
499 a8083063 Iustin Pop

500 a8083063 Iustin Pop
  """
501 56bece1f Iustin Pop
  cl = GetClient()
502 7688d0d3 Michael Hanselmann
503 a8083063 Iustin Pop
  command = " ".join(args)
504 4040a784 Iustin Pop
505 b6e88032 Michael Hanselmann
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl, nodegroup=opts.nodegroup)
506 56bece1f Iustin Pop
507 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
508 56bece1f Iustin Pop
                                                    "master_node"])
509 b3989551 Iustin Pop
510 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
511 b3989551 Iustin Pop
512 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
513 b3989551 Iustin Pop
  if master_node in nodes:
514 b3989551 Iustin Pop
    nodes.remove(master_node)
515 b3989551 Iustin Pop
    nodes.append(master_node)
516 b3989551 Iustin Pop
517 b3989551 Iustin Pop
  for name in nodes:
518 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
519 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
520 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
521 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
522 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
523 b3989551 Iustin Pop
524 b3989551 Iustin Pop
  return 0
525 a8083063 Iustin Pop
526 a8083063 Iustin Pop
527 a8083063 Iustin Pop
def VerifyCluster(opts, args):
528 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
529 a8083063 Iustin Pop

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

536 a8083063 Iustin Pop
  """
537 8d59409f Iustin Pop
  skip_checks = []
538 bf93ae69 Adeodato Simo
539 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
540 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
541 bf93ae69 Adeodato Simo
542 fcad7225 Michael Hanselmann
  cl = GetClient()
543 bf93ae69 Adeodato Simo
544 fcad7225 Michael Hanselmann
  op = opcodes.OpClusterVerify(verbose=opts.verbose,
545 fcad7225 Michael Hanselmann
                               error_codes=opts.error_codes,
546 fcad7225 Michael Hanselmann
                               debug_simulate_errors=opts.simulate_errors,
547 fcad7225 Michael Hanselmann
                               skip_checks=skip_checks,
548 93f2399e Andrea Spadaccini
                               ignore_errors=opts.ignore_errors,
549 fcad7225 Michael Hanselmann
                               group_name=opts.nodegroup)
550 fcad7225 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
551 bf93ae69 Adeodato Simo
552 fcad7225 Michael Hanselmann
  # Keep track of submitted jobs
553 fcad7225 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
554 fcad7225 Michael Hanselmann
555 fcad7225 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
556 fcad7225 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
557 bf93ae69 Adeodato Simo
558 fcad7225 Michael Hanselmann
  results = jex.GetResults()
559 ebe6cf38 Michael Hanselmann
560 ebe6cf38 Michael Hanselmann
  (bad_jobs, bad_results) = \
561 ebe6cf38 Michael Hanselmann
    map(len,
562 ebe6cf38 Michael Hanselmann
        # Convert iterators to lists
563 ebe6cf38 Michael Hanselmann
        map(list,
564 ebe6cf38 Michael Hanselmann
            # Count errors
565 ebe6cf38 Michael Hanselmann
            map(compat.partial(itertools.ifilterfalse, bool),
566 ebe6cf38 Michael Hanselmann
                # Convert result to booleans in a tuple
567 ebe6cf38 Michael Hanselmann
                zip(*((job_success, len(op_results) == 1 and op_results[0])
568 ebe6cf38 Michael Hanselmann
                      for (job_success, op_results) in results)))))
569 ebe6cf38 Michael Hanselmann
570 ebe6cf38 Michael Hanselmann
  if bad_jobs == 0 and bad_results == 0:
571 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
572 e0508c86 Guido Trotter
  else:
573 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
574 ebe6cf38 Michael Hanselmann
    if bad_jobs > 0:
575 ebe6cf38 Michael Hanselmann
      ToStdout("%s job(s) failed while verifying the cluster.", bad_jobs)
576 fcad7225 Michael Hanselmann
577 fcad7225 Michael Hanselmann
  return rcode
578 a8083063 Iustin Pop
579 a8083063 Iustin Pop
580 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
581 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
582 f4d4e184 Iustin Pop

583 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
584 469ee405 Iustin Pop
  @type args: list
585 469ee405 Iustin Pop
  @param args: should be an empty list
586 469ee405 Iustin Pop
  @rtype: int
587 469ee405 Iustin Pop
  @return: the desired exit code
588 f4d4e184 Iustin Pop

589 f4d4e184 Iustin Pop
  """
590 f1b083ce Michael Hanselmann
  cl = GetClient()
591 f1b083ce Michael Hanselmann
592 bd8210a7 Iustin Pop
  op = opcodes.OpClusterVerifyDisks()
593 f4d4e184 Iustin Pop
594 ae1a845c Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
595 ae1a845c Michael Hanselmann
596 ae1a845c Michael Hanselmann
  # Keep track of submitted jobs
597 ae1a845c Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
598 ae1a845c Michael Hanselmann
599 ae1a845c Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
600 ae1a845c Michael Hanselmann
    jex.AddJobId(None, status, job_id)
601 b63ed789 Iustin Pop
602 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
603 b63ed789 Iustin Pop
604 ae1a845c Michael Hanselmann
  for (status, result) in jex.GetResults():
605 ae1a845c Michael Hanselmann
    if not status:
606 ae1a845c Michael Hanselmann
      ToStdout("Job failed: %s", result)
607 ae1a845c Michael Hanselmann
      continue
608 ae1a845c Michael Hanselmann
609 ae1a845c Michael Hanselmann
    ((bad_nodes, instances, missing), ) = result
610 ae1a845c Michael Hanselmann
611 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
612 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
613 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
614 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
615 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
616 b63ed789 Iustin Pop
617 f4d4e184 Iustin Pop
    for iname in instances:
618 b63ed789 Iustin Pop
      if iname in missing:
619 b63ed789 Iustin Pop
        continue
620 83f5d475 Iustin Pop
      op = opcodes.OpInstanceActivateDisks(instance_name=iname)
621 f4d4e184 Iustin Pop
      try:
622 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
623 f1b083ce Michael Hanselmann
        SubmitOpCode(op, opts=opts, cl=cl)
624 f4d4e184 Iustin Pop
      except errors.GenericError, err:
625 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
626 f4d4e184 Iustin Pop
        retcode |= nret
627 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
628 b63ed789 Iustin Pop
629 ae1a845c Michael Hanselmann
    if missing:
630 ae1a845c Michael Hanselmann
      for iname, ival in missing.iteritems():
631 ae1a845c Michael Hanselmann
        all_missing = compat.all(x[0] in bad_nodes for x in ival)
632 ae1a845c Michael Hanselmann
        if all_missing:
633 ae1a845c Michael Hanselmann
          ToStdout("Instance %s cannot be verified as it lives on"
634 ae1a845c Michael Hanselmann
                   " broken nodes", iname)
635 ae1a845c Michael Hanselmann
        else:
636 ae1a845c Michael Hanselmann
          ToStdout("Instance %s has missing logical volumes:", iname)
637 ae1a845c Michael Hanselmann
          ival.sort()
638 ae1a845c Michael Hanselmann
          for node, vol in ival:
639 ae1a845c Michael Hanselmann
            if node in bad_nodes:
640 ae1a845c Michael Hanselmann
              ToStdout("\tbroken node %s /dev/%s", node, vol)
641 ae1a845c Michael Hanselmann
            else:
642 ae1a845c Michael Hanselmann
              ToStdout("\t%s /dev/%s", node, vol)
643 ae1a845c Michael Hanselmann
644 ae1a845c Michael Hanselmann
      ToStdout("You need to replace or recreate disks for all the above"
645 ae1a845c Michael Hanselmann
               " instances if this message persists after fixing broken nodes.")
646 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
647 f4d4e184 Iustin Pop
648 f4d4e184 Iustin Pop
  return retcode
649 f4d4e184 Iustin Pop
650 f4d4e184 Iustin Pop
651 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
652 60975797 Iustin Pop
  """Verify sizes of cluster disks.
653 60975797 Iustin Pop

654 60975797 Iustin Pop
  @param opts: the command line options selected by the user
655 60975797 Iustin Pop
  @type args: list
656 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
657 60975797 Iustin Pop
  @rtype: int
658 60975797 Iustin Pop
  @return: the desired exit code
659 60975797 Iustin Pop

660 60975797 Iustin Pop
  """
661 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
662 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
663 60975797 Iustin Pop
664 60975797 Iustin Pop
665 4331f6cd Michael Hanselmann
@UsesRPC
666 a8083063 Iustin Pop
def MasterFailover(opts, args):
667 a8083063 Iustin Pop
  """Failover the master node.
668 a8083063 Iustin Pop

669 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
670 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
671 a8083063 Iustin Pop
  master.
672 a8083063 Iustin Pop

673 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
674 469ee405 Iustin Pop
  @type args: list
675 469ee405 Iustin Pop
  @param args: should be an empty list
676 469ee405 Iustin Pop
  @rtype: int
677 469ee405 Iustin Pop
  @return: the desired exit code
678 469ee405 Iustin Pop

679 a8083063 Iustin Pop
  """
680 8e2524c3 Guido Trotter
  if opts.no_voting:
681 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
682 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
683 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
684 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
685 8e2524c3 Guido Trotter
    if not AskUser(usertext):
686 8e2524c3 Guido Trotter
      return 1
687 8e2524c3 Guido Trotter
688 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
689 a8083063 Iustin Pop
690 a8083063 Iustin Pop
691 4404ffad Iustin Pop
def MasterPing(opts, args):
692 4404ffad Iustin Pop
  """Checks if the master is alive.
693 4404ffad Iustin Pop

694 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
695 4404ffad Iustin Pop
  @type args: list
696 4404ffad Iustin Pop
  @param args: should be an empty list
697 4404ffad Iustin Pop
  @rtype: int
698 4404ffad Iustin Pop
  @return: the desired exit code
699 4404ffad Iustin Pop

700 4404ffad Iustin Pop
  """
701 4404ffad Iustin Pop
  try:
702 4404ffad Iustin Pop
    cl = GetClient()
703 4404ffad Iustin Pop
    cl.QueryClusterInfo()
704 4404ffad Iustin Pop
    return 0
705 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
706 4404ffad Iustin Pop
    return 1
707 4404ffad Iustin Pop
708 4404ffad Iustin Pop
709 73415719 Iustin Pop
def SearchTags(opts, args):
710 73415719 Iustin Pop
  """Searches the tags on all the cluster.
711 73415719 Iustin Pop

712 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
713 469ee405 Iustin Pop
  @type args: list
714 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
715 469ee405 Iustin Pop
  @rtype: int
716 469ee405 Iustin Pop
  @return: the desired exit code
717 469ee405 Iustin Pop

718 73415719 Iustin Pop
  """
719 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
720 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
721 73415719 Iustin Pop
  if not result:
722 73415719 Iustin Pop
    return 1
723 73415719 Iustin Pop
  result = list(result)
724 73415719 Iustin Pop
  result.sort()
725 73415719 Iustin Pop
  for path, tag in result:
726 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
727 73415719 Iustin Pop
728 73415719 Iustin Pop
729 b6267745 Andrea Spadaccini
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
730 b6267745 Andrea Spadaccini
  """Reads and verifies an X509 certificate.
731 b6267745 Andrea Spadaccini

732 b6267745 Andrea Spadaccini
  @type cert_filename: string
733 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
734 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
735 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
736 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
737 b6267745 Andrea Spadaccini
                             the public certificate
738 b6267745 Andrea Spadaccini
  @rtype: string
739 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
740 b6267745 Andrea Spadaccini

741 b6267745 Andrea Spadaccini
  """
742 b6267745 Andrea Spadaccini
  try:
743 b6267745 Andrea Spadaccini
    pem = utils.ReadFile(cert_filename)
744 b6267745 Andrea Spadaccini
  except IOError, err:
745 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
746 b6267745 Andrea Spadaccini
                               "Unable to read certificate: %s" % str(err))
747 b6267745 Andrea Spadaccini
748 b6267745 Andrea Spadaccini
  try:
749 b6267745 Andrea Spadaccini
    OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
750 b6267745 Andrea Spadaccini
  except Exception, err:
751 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
752 b6267745 Andrea Spadaccini
                               "Unable to load certificate: %s" % str(err))
753 b6267745 Andrea Spadaccini
754 b6267745 Andrea Spadaccini
  if verify_private_key:
755 b6267745 Andrea Spadaccini
    try:
756 b6267745 Andrea Spadaccini
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, pem)
757 b6267745 Andrea Spadaccini
    except Exception, err:
758 b6267745 Andrea Spadaccini
      raise errors.X509CertError(cert_filename,
759 b6267745 Andrea Spadaccini
                                 "Unable to load private key: %s" % str(err))
760 b6267745 Andrea Spadaccini
761 b6267745 Andrea Spadaccini
  return pem
762 b6267745 Andrea Spadaccini
763 b6267745 Andrea Spadaccini
764 b6267745 Andrea Spadaccini
def _RenewCrypto(new_cluster_cert, new_rapi_cert, #pylint: disable=R0911
765 b6267745 Andrea Spadaccini
                 rapi_cert_filename, new_spice_cert, spice_cert_filename,
766 b6267745 Andrea Spadaccini
                 spice_cacert_filename, new_confd_hmac_key, new_cds,
767 b6267745 Andrea Spadaccini
                 cds_filename, force):
768 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
769 6d4a1656 Michael Hanselmann

770 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
771 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
772 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
773 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
774 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
775 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
776 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
777 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
778 b6267745 Andrea Spadaccini
  @type spice_cert_filename: string
779 b6267745 Andrea Spadaccini
  @param spice_cert_filename: Path to file containing new SPICE certificate
780 b6267745 Andrea Spadaccini
  @type spice_cacert_filename: string
781 b6267745 Andrea Spadaccini
  @param spice_cacert_filename: Path to file containing the certificate of the
782 b6267745 Andrea Spadaccini
                                CA that signed the SPICE certificate
783 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
784 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
785 3db3eb2a Michael Hanselmann
  @type new_cds: bool
786 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
787 3db3eb2a Michael Hanselmann
  @type cds_filename: string
788 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
789 6d4a1656 Michael Hanselmann
  @type force: bool
790 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
791 6d4a1656 Michael Hanselmann

792 6d4a1656 Michael Hanselmann
  """
793 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
794 6e060e15 Andrea Spadaccini
    ToStderr("Only one of the --new-rapi-certificate and --rapi-certificate"
795 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
796 6d4a1656 Michael Hanselmann
    return 1
797 6d4a1656 Michael Hanselmann
798 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
799 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
800 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
801 3db3eb2a Michael Hanselmann
             " the same time.")
802 3db3eb2a Michael Hanselmann
    return 1
803 3db3eb2a Michael Hanselmann
804 b6267745 Andrea Spadaccini
  if new_spice_cert and (spice_cert_filename or spice_cacert_filename):
805 b6267745 Andrea Spadaccini
    ToStderr("When using --new-spice-certificate, the --spice-certificate"
806 b6267745 Andrea Spadaccini
             " and --spice-ca-certificate must not be used.")
807 b6267745 Andrea Spadaccini
    return 1
808 6d4a1656 Michael Hanselmann
809 b6267745 Andrea Spadaccini
  if bool(spice_cacert_filename) ^ bool(spice_cert_filename):
810 b6267745 Andrea Spadaccini
    ToStderr("Both --spice-certificate and --spice-ca-certificate must be"
811 b6267745 Andrea Spadaccini
             " specified.")
812 b6267745 Andrea Spadaccini
    return 1
813 6d4a1656 Michael Hanselmann
814 b6267745 Andrea Spadaccini
  rapi_cert_pem, spice_cert_pem, spice_cacert_pem = (None, None, None)
815 b6267745 Andrea Spadaccini
  try:
816 b6267745 Andrea Spadaccini
    if rapi_cert_filename:
817 b6267745 Andrea Spadaccini
      rapi_cert_pem = _ReadAndVerifyCert(rapi_cert_filename, True)
818 b6267745 Andrea Spadaccini
    if spice_cert_filename:
819 b6267745 Andrea Spadaccini
      spice_cert_pem = _ReadAndVerifyCert(spice_cert_filename, True)
820 b6267745 Andrea Spadaccini
      spice_cacert_pem = _ReadAndVerifyCert(spice_cacert_filename)
821 b6267745 Andrea Spadaccini
  except errors.X509CertError, err:
822 b6267745 Andrea Spadaccini
    ToStderr("Unable to load X509 certificate from %s: %s", err[0], err[1])
823 b6267745 Andrea Spadaccini
    return 1
824 6d4a1656 Michael Hanselmann
825 3db3eb2a Michael Hanselmann
  if cds_filename:
826 3db3eb2a Michael Hanselmann
    try:
827 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
828 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
829 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
830 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
831 3db3eb2a Michael Hanselmann
      return 1
832 3db3eb2a Michael Hanselmann
  else:
833 3db3eb2a Michael Hanselmann
    cds = None
834 3db3eb2a Michael Hanselmann
835 6d4a1656 Michael Hanselmann
  if not force:
836 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
837 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
838 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
839 6d4a1656 Michael Hanselmann
      return 1
840 6d4a1656 Michael Hanselmann
841 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
842 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
843 b6267745 Andrea Spadaccini
    bootstrap.GenerateClusterCrypto(new_cluster_cert,
844 b6267745 Andrea Spadaccini
                                    new_rapi_cert,
845 b6267745 Andrea Spadaccini
                                    new_spice_cert,
846 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
847 3db3eb2a Michael Hanselmann
                                    new_cds,
848 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
849 b6267745 Andrea Spadaccini
                                    spice_cert_pem=spice_cert_pem,
850 b6267745 Andrea Spadaccini
                                    spice_cacert_pem=spice_cacert_pem,
851 3db3eb2a Michael Hanselmann
                                    cds=cds)
852 6d4a1656 Michael Hanselmann
853 6d4a1656 Michael Hanselmann
    files_to_copy = []
854 6d4a1656 Michael Hanselmann
855 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
856 168c1de2 Michael Hanselmann
      files_to_copy.append(constants.NODED_CERT_FILE)
857 6d4a1656 Michael Hanselmann
858 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
859 6d4a1656 Michael Hanselmann
      files_to_copy.append(constants.RAPI_CERT_FILE)
860 6d4a1656 Michael Hanselmann
861 b6267745 Andrea Spadaccini
    if new_spice_cert or spice_cert_pem:
862 b6267745 Andrea Spadaccini
      files_to_copy.append(constants.SPICE_CERT_FILE)
863 b6267745 Andrea Spadaccini
      files_to_copy.append(constants.SPICE_CACERT_FILE)
864 b6267745 Andrea Spadaccini
865 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
866 6b7d5878 Michael Hanselmann
      files_to_copy.append(constants.CONFD_HMAC_KEY)
867 6d4a1656 Michael Hanselmann
868 3db3eb2a Michael Hanselmann
    if new_cds or cds:
869 3db3eb2a Michael Hanselmann
      files_to_copy.append(constants.CLUSTER_DOMAIN_SECRET_FILE)
870 3db3eb2a Michael Hanselmann
871 6d4a1656 Michael Hanselmann
    if files_to_copy:
872 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
873 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
874 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
875 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
876 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
877 6d4a1656 Michael Hanselmann
878 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
879 6d4a1656 Michael Hanselmann
880 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
881 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
882 6d4a1656 Michael Hanselmann
883 6d4a1656 Michael Hanselmann
  return 0
884 6d4a1656 Michael Hanselmann
885 6d4a1656 Michael Hanselmann
886 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
887 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
888 6d4a1656 Michael Hanselmann

889 6d4a1656 Michael Hanselmann
  """
890 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
891 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
892 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
893 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
894 b6267745 Andrea Spadaccini
                      opts.spice_cert,
895 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
896 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
897 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
898 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
899 6d4a1656 Michael Hanselmann
                      opts.force)
900 6d4a1656 Michael Hanselmann
901 6d4a1656 Michael Hanselmann
902 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
903 90b6aa3a Manuel Franceschini
  """Modify the cluster.
904 90b6aa3a Manuel Franceschini

905 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
906 469ee405 Iustin Pop
  @type args: list
907 469ee405 Iustin Pop
  @param args: should be an empty list
908 469ee405 Iustin Pop
  @rtype: int
909 469ee405 Iustin Pop
  @return: the desired exit code
910 90b6aa3a Manuel Franceschini

911 90b6aa3a Manuel Franceschini
  """
912 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
913 ed14ed48 Luca Bigliardi
          not opts.drbd_storage or opts.drbd_helper or
914 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
915 bc5d0215 Andrea Spadaccini
          opts.beparams or opts.nicparams or
916 bc5d0215 Andrea Spadaccini
          opts.ndparams or opts.diskparams or
917 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
918 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
919 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
920 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
921 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
922 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
923 b883637f René Nussbaumer
          opts.reserved_lvs is not None or
924 38f9d2cf Guido Trotter
          opts.master_netdev is not None or
925 5a8648eb Andrea Spadaccini
          opts.master_netmask is not None or
926 bf689b7a Andrea Spadaccini
          opts.use_external_mip_script is not None or
927 2da9f556 René Nussbaumer
          opts.prealloc_wipe_disks is not None or
928 2da9f556 René Nussbaumer
          opts.hv_state or
929 e1a6850f Agata Murawska
          opts.disk_state or
930 e1a6850f Agata Murawska
          opts.ispecs_mem_size is not None or
931 e1a6850f Agata Murawska
          opts.ispecs_cpu_count is not None or
932 e1a6850f Agata Murawska
          opts.ispecs_disk_count is not None or
933 e1a6850f Agata Murawska
          opts.ispecs_disk_size is not None or
934 e1a6850f Agata Murawska
          opts.ispecs_nic_count is not None):
935 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
936 90b6aa3a Manuel Franceschini
    return 1
937 90b6aa3a Manuel Franceschini
938 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
939 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
940 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
941 90b6aa3a Manuel Franceschini
    return 1
942 6d4a1656 Michael Hanselmann
943 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
944 6d4a1656 Michael Hanselmann
    vg_name = ""
945 90b6aa3a Manuel Franceschini
946 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
947 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
948 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
949 ed14ed48 Luca Bigliardi
    return 1
950 ed14ed48 Luca Bigliardi
951 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage:
952 ed14ed48 Luca Bigliardi
    drbd_helper = ""
953 ed14ed48 Luca Bigliardi
954 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
955 779c15bb Iustin Pop
  if hvlist is not None:
956 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
957 779c15bb Iustin Pop
958 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
959 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
960 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
961 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
962 779c15bb Iustin Pop
963 bc5d0215 Andrea Spadaccini
  diskparams = dict(opts.diskparams)
964 bc5d0215 Andrea Spadaccini
965 bc5d0215 Andrea Spadaccini
  for dt_params in hvparams.values():
966 bc5d0215 Andrea Spadaccini
    utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
967 bc5d0215 Andrea Spadaccini
968 779c15bb Iustin Pop
  beparams = opts.beparams
969 b2e233a5 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT)
970 779c15bb Iustin Pop
971 5af3da74 Guido Trotter
  nicparams = opts.nicparams
972 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
973 5af3da74 Guido Trotter
974 6204ee71 René Nussbaumer
  ndparams = opts.ndparams
975 6204ee71 René Nussbaumer
  if ndparams is not None:
976 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
977 1338f2b4 Balazs Lecz
978 e1a6850f Agata Murawska
  ipolicy = \
979 e1a6850f Agata Murawska
    objects.CreateIPolicyFromOpts(ispecs_mem_size=opts.ispecs_mem_size,
980 e1a6850f Agata Murawska
                                  ispecs_cpu_count=opts.ispecs_cpu_count,
981 e1a6850f Agata Murawska
                                  ispecs_disk_count=opts.ispecs_disk_count,
982 e1a6850f Agata Murawska
                                  ispecs_disk_size=opts.ispecs_disk_size,
983 e1a6850f Agata Murawska
                                  ispecs_nic_count=opts.ispecs_nic_count)
984 e1a6850f Agata Murawska
  for value in ipolicy.values():
985 e1a6850f Agata Murawska
    utils.ForceDictType(value, constants.ISPECS_PARAMETER_TYPES)
986 e1a6850f Agata Murawska
987 3953242f Iustin Pop
  mnh = opts.maintain_node_health
988 3953242f Iustin Pop
989 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
990 1338f2b4 Balazs Lecz
  if uid_pool is not None:
991 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
992 1338f2b4 Balazs Lecz
993 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
994 fdad8c4d Balazs Lecz
  if add_uids is not None:
995 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
996 fdad8c4d Balazs Lecz
997 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
998 fdad8c4d Balazs Lecz
  if remove_uids is not None:
999 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
1000 fdad8c4d Balazs Lecz
1001 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
1002 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
1003 f38ea602 Iustin Pop
      opts.reserved_lvs = []
1004 f38ea602 Iustin Pop
    else:
1005 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
1006 f38ea602 Iustin Pop
1007 5a8648eb Andrea Spadaccini
  if opts.master_netmask is not None:
1008 5a8648eb Andrea Spadaccini
    try:
1009 5a8648eb Andrea Spadaccini
      opts.master_netmask = int(opts.master_netmask)
1010 5a8648eb Andrea Spadaccini
    except ValueError:
1011 5a8648eb Andrea Spadaccini
      ToStderr("The --master-netmask option expects an int parameter.")
1012 5a8648eb Andrea Spadaccini
      return 1
1013 5a8648eb Andrea Spadaccini
1014 bf689b7a Andrea Spadaccini
  ext_ip_script = opts.use_external_mip_script
1015 bf689b7a Andrea Spadaccini
1016 2da9f556 René Nussbaumer
  if opts.disk_state:
1017 2da9f556 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
1018 2da9f556 René Nussbaumer
  else:
1019 2da9f556 René Nussbaumer
    disk_state = {}
1020 2da9f556 René Nussbaumer
1021 2da9f556 René Nussbaumer
  hv_state = dict(opts.hv_state)
1022 2da9f556 René Nussbaumer
1023 a6682fdc Iustin Pop
  op = opcodes.OpClusterSetParams(vg_name=vg_name,
1024 ed14ed48 Luca Bigliardi
                                  drbd_helper=drbd_helper,
1025 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
1026 779c15bb Iustin Pop
                                  hvparams=hvparams,
1027 17463d22 René Nussbaumer
                                  os_hvp=None,
1028 4b7735f9 Iustin Pop
                                  beparams=beparams,
1029 5af3da74 Guido Trotter
                                  nicparams=nicparams,
1030 6204ee71 René Nussbaumer
                                  ndparams=ndparams,
1031 bc5d0215 Andrea Spadaccini
                                  diskparams=diskparams,
1032 e1a6850f Agata Murawska
                                  ipolicy=ipolicy,
1033 3953242f Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size,
1034 1338f2b4 Balazs Lecz
                                  maintain_node_health=mnh,
1035 fdad8c4d Balazs Lecz
                                  uid_pool=uid_pool,
1036 fdad8c4d Balazs Lecz
                                  add_uids=add_uids,
1037 bf4af505 Apollon Oikonomopoulos
                                  remove_uids=remove_uids,
1038 f38ea602 Iustin Pop
                                  default_iallocator=opts.default_iallocator,
1039 b883637f René Nussbaumer
                                  prealloc_wipe_disks=opts.prealloc_wipe_disks,
1040 38f9d2cf Guido Trotter
                                  master_netdev=opts.master_netdev,
1041 5a8648eb Andrea Spadaccini
                                  master_netmask=opts.master_netmask,
1042 bf689b7a Andrea Spadaccini
                                  reserved_lvs=opts.reserved_lvs,
1043 bf689b7a Andrea Spadaccini
                                  use_external_mip_script=ext_ip_script,
1044 2da9f556 René Nussbaumer
                                  hv_state=hv_state,
1045 2da9f556 René Nussbaumer
                                  disk_state=disk_state,
1046 bf689b7a Andrea Spadaccini
                                  )
1047 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
1048 90b6aa3a Manuel Franceschini
  return 0
1049 90b6aa3a Manuel Franceschini
1050 90b6aa3a Manuel Franceschini
1051 3ccafd0e Iustin Pop
def QueueOps(opts, args):
1052 3ccafd0e Iustin Pop
  """Queue operations.
1053 3ccafd0e Iustin Pop

1054 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1055 469ee405 Iustin Pop
  @type args: list
1056 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1057 469ee405 Iustin Pop
  @rtype: int
1058 469ee405 Iustin Pop
  @return: the desired exit code
1059 469ee405 Iustin Pop

1060 3ccafd0e Iustin Pop
  """
1061 3ccafd0e Iustin Pop
  command = args[0]
1062 3ccafd0e Iustin Pop
  client = GetClient()
1063 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
1064 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
1065 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
1066 3ccafd0e Iustin Pop
  elif command == "info":
1067 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
1068 3ccafd0e Iustin Pop
    if result[0]:
1069 3a24c527 Iustin Pop
      val = "set"
1070 3ccafd0e Iustin Pop
    else:
1071 3a24c527 Iustin Pop
      val = "unset"
1072 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
1073 2e668b38 Guido Trotter
  else:
1074 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1075 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1076 2e668b38 Guido Trotter
1077 3ccafd0e Iustin Pop
  return 0
1078 3ccafd0e Iustin Pop
1079 95b2e626 Michael Hanselmann
1080 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
1081 28b498cd Michael Hanselmann
  if until is None or until < time.time():
1082 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
1083 28b498cd Michael Hanselmann
  else:
1084 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
1085 28b498cd Michael Hanselmann
1086 28b498cd Michael Hanselmann
1087 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
1088 95b2e626 Michael Hanselmann
  """Watcher operations.
1089 95b2e626 Michael Hanselmann

1090 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1091 95b2e626 Michael Hanselmann
  @type args: list
1092 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1093 95b2e626 Michael Hanselmann
  @rtype: int
1094 95b2e626 Michael Hanselmann
  @return: the desired exit code
1095 95b2e626 Michael Hanselmann

1096 95b2e626 Michael Hanselmann
  """
1097 95b2e626 Michael Hanselmann
  command = args[0]
1098 95b2e626 Michael Hanselmann
  client = GetClient()
1099 95b2e626 Michael Hanselmann
1100 95b2e626 Michael Hanselmann
  if command == "continue":
1101 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
1102 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
1103 95b2e626 Michael Hanselmann
1104 95b2e626 Michael Hanselmann
  elif command == "pause":
1105 95b2e626 Michael Hanselmann
    if len(args) < 2:
1106 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
1107 95b2e626 Michael Hanselmann
1108 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
1109 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
1110 95b2e626 Michael Hanselmann
1111 95b2e626 Michael Hanselmann
  elif command == "info":
1112 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
1113 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
1114 95b2e626 Michael Hanselmann
1115 95b2e626 Michael Hanselmann
  else:
1116 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1117 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1118 95b2e626 Michael Hanselmann
1119 95b2e626 Michael Hanselmann
  return 0
1120 95b2e626 Michael Hanselmann
1121 95b2e626 Michael Hanselmann
1122 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
1123 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
1124 66d1f035 René Nussbaumer

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

1130 66d1f035 René Nussbaumer
  """
1131 66d1f035 René Nussbaumer
  if power:
1132 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
1133 66d1f035 René Nussbaumer
  else:
1134 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
1135 66d1f035 René Nussbaumer
1136 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
1137 66d1f035 René Nussbaumer
                            command=command,
1138 66d1f035 René Nussbaumer
                            ignore_status=True,
1139 cfed3b9f René Nussbaumer
                            timeout=opts.oob_timeout,
1140 cfed3b9f René Nussbaumer
                            power_delay=opts.power_delay)
1141 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
1142 66d1f035 René Nussbaumer
  errs = 0
1143 66d1f035 René Nussbaumer
  for node_result in result:
1144 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
1145 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
1146 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
1147 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
1148 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
1149 66d1f035 René Nussbaumer
      errs += 1
1150 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
1151 66d1f035 René Nussbaumer
               node_name)
1152 66d1f035 René Nussbaumer
1153 66d1f035 René Nussbaumer
  if errs > 0:
1154 66d1f035 René Nussbaumer
    return False
1155 66d1f035 René Nussbaumer
1156 66d1f035 René Nussbaumer
  return True
1157 66d1f035 René Nussbaumer
1158 66d1f035 René Nussbaumer
1159 66d1f035 René Nussbaumer
def _InstanceStart(opts, inst_list, start):
1160 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
1161 66d1f035 René Nussbaumer

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

1167 66d1f035 René Nussbaumer
  """
1168 66d1f035 René Nussbaumer
  if start:
1169 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
1170 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
1171 66d1f035 René Nussbaumer
  else:
1172 fcecea0b René Nussbaumer
    opcls = compat.partial(opcodes.OpInstanceShutdown,
1173 fcecea0b René Nussbaumer
                           timeout=opts.shutdown_timeout)
1174 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
1175 66d1f035 René Nussbaumer
1176 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
1177 66d1f035 René Nussbaumer
1178 66d1f035 René Nussbaumer
  for inst in inst_list:
1179 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
1180 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
1181 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
1182 66d1f035 René Nussbaumer
1183 66d1f035 René Nussbaumer
  results = jex.GetResults()
1184 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
1185 66d1f035 René Nussbaumer
1186 66d1f035 René Nussbaumer
  if bad_cnt == 0:
1187 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
1188 66d1f035 René Nussbaumer
  else:
1189 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
1190 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
1191 66d1f035 René Nussbaumer
             len(results))
1192 66d1f035 René Nussbaumer
    return False
1193 66d1f035 René Nussbaumer
1194 66d1f035 René Nussbaumer
  return True
1195 66d1f035 René Nussbaumer
1196 66d1f035 René Nussbaumer
1197 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
1198 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
1199 66d1f035 René Nussbaumer

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

1202 66d1f035 René Nussbaumer
  """
1203 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1204 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1205 66d1f035 René Nussbaumer
    """Init the object.
1206 66d1f035 René Nussbaumer

1207 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1208 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1209 66d1f035 René Nussbaumer
    @type node2ip: dict
1210 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1211 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1212 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1213 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1214 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1215 66d1f035 René Nussbaumer

1216 66d1f035 René Nussbaumer
    """
1217 66d1f035 René Nussbaumer
    self.down = set(node_list)
1218 66d1f035 René Nussbaumer
    self.up = set()
1219 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1220 66d1f035 René Nussbaumer
    self.success = True
1221 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1222 66d1f035 René Nussbaumer
    self.port = port
1223 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1224 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1225 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1226 66d1f035 René Nussbaumer
1227 66d1f035 René Nussbaumer
  def __call__(self):
1228 66d1f035 René Nussbaumer
    """When called we run action_cb.
1229 66d1f035 René Nussbaumer

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

1232 66d1f035 René Nussbaumer
    """
1233 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1234 66d1f035 René Nussbaumer
      self.success = False
1235 66d1f035 René Nussbaumer
1236 66d1f035 René Nussbaumer
    if self.down:
1237 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1238 66d1f035 René Nussbaumer
    else:
1239 66d1f035 René Nussbaumer
      return self.success
1240 66d1f035 René Nussbaumer
1241 66d1f035 René Nussbaumer
  def Wait(self, secs):
1242 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1243 66d1f035 René Nussbaumer

1244 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1245 66d1f035 René Nussbaumer

1246 66d1f035 René Nussbaumer
    """
1247 66d1f035 René Nussbaumer
    start = time.time()
1248 66d1f035 René Nussbaumer
    for node in self.down:
1249 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1250 66d1f035 René Nussbaumer
                       live_port_needed=True):
1251 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1252 66d1f035 René Nussbaumer
        self.up.add(node)
1253 66d1f035 René Nussbaumer
        self.down -= self.up
1254 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1255 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1256 66d1f035 René Nussbaumer
        return
1257 66d1f035 René Nussbaumer
1258 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1259 66d1f035 René Nussbaumer
1260 66d1f035 René Nussbaumer
1261 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1262 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1263 66d1f035 René Nussbaumer

1264 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1265 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1266 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1267 66d1f035 René Nussbaumer

1268 66d1f035 René Nussbaumer
  """
1269 66d1f035 René Nussbaumer
  client = GetClient()
1270 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1271 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1272 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1273 66d1f035 René Nussbaumer
  else:
1274 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1275 66d1f035 René Nussbaumer
1276 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1277 66d1f035 René Nussbaumer
                 for node in node_list)
1278 66d1f035 René Nussbaumer
1279 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1280 8e74adce René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port,
1281 8e74adce René Nussbaumer
                                        ToStdout)
1282 66d1f035 René Nussbaumer
1283 66d1f035 René Nussbaumer
  try:
1284 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1285 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1286 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1287 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1288 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1289 66d1f035 René Nussbaumer
    return False
1290 66d1f035 René Nussbaumer
1291 66d1f035 René Nussbaumer
1292 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1293 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1294 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1295 66d1f035 René Nussbaumer

1296 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1297 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1298 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1299 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1300 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1301 66d1f035 René Nussbaumer

1302 66d1f035 René Nussbaumer
  """
1303 66d1f035 René Nussbaumer
  start_inst_list = []
1304 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1305 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1306 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1307 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1308 66d1f035 René Nussbaumer
1309 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1310 66d1f035 René Nussbaumer
    del inst_map[inst]
1311 66d1f035 René Nussbaumer
1312 66d1f035 René Nussbaumer
  if start_inst_list:
1313 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1314 66d1f035 René Nussbaumer
1315 66d1f035 René Nussbaumer
  return True
1316 66d1f035 René Nussbaumer
1317 66d1f035 René Nussbaumer
1318 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1319 66d1f035 René Nussbaumer
  """Does the actual power on.
1320 66d1f035 René Nussbaumer

1321 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1322 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1323 66d1f035 René Nussbaumer
                         OOB)
1324 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1325 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1326 66d1f035 René Nussbaumer
  @return: The desired exit status
1327 66d1f035 René Nussbaumer

1328 66d1f035 René Nussbaumer
  """
1329 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1330 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1331 66d1f035 René Nussbaumer
             " manually if needed")
1332 66d1f035 René Nussbaumer
1333 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1334 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1335 66d1f035 René Nussbaumer
1336 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1337 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1338 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1339 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1340 66d1f035 René Nussbaumer
1341 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1342 66d1f035 René Nussbaumer
1343 66d1f035 René Nussbaumer
1344 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1345 66d1f035 René Nussbaumer
  """Does the actual power off.
1346 66d1f035 René Nussbaumer

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

1352 66d1f035 René Nussbaumer
  """
1353 66d1f035 René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False):
1354 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1355 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1356 66d1f035 René Nussbaumer
1357 66d1f035 René Nussbaumer
  if not node_list:
1358 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1359 66d1f035 René Nussbaumer
1360 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1361 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1362 66d1f035 René Nussbaumer
  else:
1363 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1364 66d1f035 René Nussbaumer
1365 66d1f035 René Nussbaumer
1366 66d1f035 René Nussbaumer
def Epo(opts, args):
1367 66d1f035 René Nussbaumer
  """EPO operations.
1368 66d1f035 René Nussbaumer

1369 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1370 66d1f035 René Nussbaumer
  @type args: list
1371 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1372 66d1f035 René Nussbaumer
  @rtype: int
1373 66d1f035 René Nussbaumer
  @return: the desired exit code
1374 66d1f035 René Nussbaumer

1375 66d1f035 René Nussbaumer
  """
1376 66d1f035 René Nussbaumer
  if opts.groups and opts.show_all:
1377 66d1f035 René Nussbaumer
    ToStderr("Only one of --groups or --all are allowed")
1378 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1379 66d1f035 René Nussbaumer
  elif args and opts.show_all:
1380 66d1f035 René Nussbaumer
    ToStderr("Arguments in combination with --all are not allowed")
1381 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1382 66d1f035 René Nussbaumer
1383 66d1f035 René Nussbaumer
  client = GetClient()
1384 66d1f035 René Nussbaumer
1385 66d1f035 René Nussbaumer
  if opts.groups:
1386 66d1f035 René Nussbaumer
    node_query_list = itertools.chain(*client.QueryGroups(names=args,
1387 66d1f035 René Nussbaumer
                                                          fields=["node_list"],
1388 66d1f035 René Nussbaumer
                                                          use_locking=False))
1389 66d1f035 René Nussbaumer
  else:
1390 66d1f035 René Nussbaumer
    node_query_list = args
1391 66d1f035 René Nussbaumer
1392 66d1f035 René Nussbaumer
  result = client.QueryNodes(names=node_query_list,
1393 66d1f035 René Nussbaumer
                             fields=["name", "master", "pinst_list",
1394 66d1f035 René Nussbaumer
                                     "sinst_list", "powered", "offline"],
1395 66d1f035 René Nussbaumer
                             use_locking=False)
1396 66d1f035 René Nussbaumer
  node_list = []
1397 66d1f035 René Nussbaumer
  inst_map = {}
1398 66d1f035 René Nussbaumer
  for (idx, (node, master, pinsts, sinsts, powered,
1399 66d1f035 René Nussbaumer
             offline)) in enumerate(result):
1400 66d1f035 René Nussbaumer
    # Normalize the node_query_list as well
1401 66d1f035 René Nussbaumer
    if not opts.show_all:
1402 66d1f035 René Nussbaumer
      node_query_list[idx] = node
1403 66d1f035 René Nussbaumer
    if not offline:
1404 66d1f035 René Nussbaumer
      for inst in (pinsts + sinsts):
1405 66d1f035 René Nussbaumer
        if inst in inst_map:
1406 66d1f035 René Nussbaumer
          if not master:
1407 66d1f035 René Nussbaumer
            inst_map[inst].add(node)
1408 66d1f035 René Nussbaumer
        elif master:
1409 66d1f035 René Nussbaumer
          inst_map[inst] = set()
1410 66d1f035 René Nussbaumer
        else:
1411 66d1f035 René Nussbaumer
          inst_map[inst] = set([node])
1412 66d1f035 René Nussbaumer
1413 66d1f035 René Nussbaumer
    if master and opts.on:
1414 66d1f035 René Nussbaumer
      # We ignore the master for turning on the machines, in fact we are
1415 66d1f035 René Nussbaumer
      # already operating on the master at this point :)
1416 66d1f035 René Nussbaumer
      continue
1417 66d1f035 René Nussbaumer
    elif master and not opts.show_all:
1418 66d1f035 René Nussbaumer
      ToStderr("%s is the master node, please do a master-failover to another"
1419 66d1f035 René Nussbaumer
               " node not affected by the EPO or use --all if you intend to"
1420 66d1f035 René Nussbaumer
               " shutdown the whole cluster", node)
1421 66d1f035 René Nussbaumer
      return constants.EXIT_FAILURE
1422 66d1f035 René Nussbaumer
    elif powered is None:
1423 66d1f035 René Nussbaumer
      ToStdout("Node %s does not support out-of-band handling, it can not be"
1424 66d1f035 René Nussbaumer
               " handled in a fully automated manner", node)
1425 66d1f035 René Nussbaumer
    elif powered == opts.on:
1426 66d1f035 René Nussbaumer
      ToStdout("Node %s is already in desired power state, skipping", node)
1427 66d1f035 René Nussbaumer
    elif not offline or (offline and powered):
1428 66d1f035 René Nussbaumer
      node_list.append(node)
1429 66d1f035 René Nussbaumer
1430 66d1f035 René Nussbaumer
  if not opts.force and not ConfirmOperation(node_query_list, "nodes", "epo"):
1431 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1432 66d1f035 René Nussbaumer
1433 66d1f035 René Nussbaumer
  if opts.on:
1434 66d1f035 René Nussbaumer
    return _EpoOn(opts, node_query_list, node_list, inst_map)
1435 66d1f035 René Nussbaumer
  else:
1436 66d1f035 René Nussbaumer
    return _EpoOff(opts, node_list, inst_map)
1437 66d1f035 René Nussbaumer
1438 32017174 Agata Murawska
INSTANCE_POLICY_OPTS = [
1439 32017174 Agata Murawska
  SPECS_CPU_COUNT_OPT,
1440 32017174 Agata Murawska
  SPECS_DISK_COUNT_OPT,
1441 32017174 Agata Murawska
  SPECS_DISK_SIZE_OPT,
1442 32017174 Agata Murawska
  SPECS_MEM_SIZE_OPT,
1443 32017174 Agata Murawska
  SPECS_NIC_COUNT_OPT,
1444 32017174 Agata Murawska
  ]
1445 66d1f035 René Nussbaumer
1446 a8083063 Iustin Pop
commands = {
1447 d0c8c01d Iustin Pop
  "init": (
1448 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
1449 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
1450 5a8648eb Andrea Spadaccini
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, MASTER_NETMASK_OPT,
1451 5a8648eb Andrea Spadaccini
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT,
1452 5a8648eb Andrea Spadaccini
     NOMODIFY_SSH_SETUP_OPT, SECONDARY_IP_OPT, VG_NAME_OPT,
1453 5a8648eb Andrea Spadaccini
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
1454 6204ee71 René Nussbaumer
     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
1455 bc5d0215 Andrea Spadaccini
     NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT, USE_EXTERNAL_MIP_SCRIPT,
1456 32017174 Agata Murawska
     DISK_PARAMS_OPT] + INSTANCE_POLICY_OPTS,
1457 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
1458 d0c8c01d Iustin Pop
  "destroy": (
1459 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
1460 6ea815cf Iustin Pop
    "", "Destroy cluster"),
1461 d0c8c01d Iustin Pop
  "rename": (
1462 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
1463 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
1464 6ea815cf Iustin Pop
    "<new_name>",
1465 6ea815cf Iustin Pop
    "Renames the cluster"),
1466 d0c8c01d Iustin Pop
  "redist-conf": (
1467 aa06f8c6 Michael Hanselmann
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1468 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
1469 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
1470 d0c8c01d Iustin Pop
  "verify": (
1471 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
1472 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
1473 93f2399e Andrea Spadaccini
     DRY_RUN_OPT, PRIORITY_OPT, NODEGROUP_OPT, IGNORE_ERRORS_OPT],
1474 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
1475 d0c8c01d Iustin Pop
  "verify-disks": (
1476 aa06f8c6 Michael Hanselmann
    VerifyDisks, ARGS_NONE, [PRIORITY_OPT],
1477 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
1478 d0c8c01d Iustin Pop
  "repair-disk-sizes": (
1479 aa06f8c6 Michael Hanselmann
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
1480 eb5ac108 Michael Hanselmann
    "[instance...]", "Updates mismatches in recorded disk sizes"),
1481 d0c8c01d Iustin Pop
  "master-failover": (
1482 064c21f8 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT],
1483 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
1484 d0c8c01d Iustin Pop
  "master-ping": (
1485 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
1486 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
1487 d0c8c01d Iustin Pop
  "version": (
1488 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
1489 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
1490 d0c8c01d Iustin Pop
  "getmaster": (
1491 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
1492 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
1493 d0c8c01d Iustin Pop
  "copyfile": (
1494 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
1495 b6e88032 Michael Hanselmann
    [NODE_LIST_OPT, USE_REPL_NET_OPT, NODEGROUP_OPT],
1496 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
1497 d0c8c01d Iustin Pop
  "command": (
1498 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
1499 b6e88032 Michael Hanselmann
    [NODE_LIST_OPT, NODEGROUP_OPT],
1500 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
1501 d0c8c01d Iustin Pop
  "info": (
1502 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
1503 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
1504 d0c8c01d Iustin Pop
  "list-tags": (
1505 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
1506 d0c8c01d Iustin Pop
  "add-tags": (
1507 aa06f8c6 Michael Hanselmann
    AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
1508 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
1509 d0c8c01d Iustin Pop
  "remove-tags": (
1510 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
1511 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
1512 d0c8c01d Iustin Pop
  "search-tags": (
1513 aa06f8c6 Michael Hanselmann
    SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "",
1514 aa06f8c6 Michael Hanselmann
    "Searches the tags on all objects on"
1515 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
1516 d0c8c01d Iustin Pop
  "queue": (
1517 6ea815cf Iustin Pop
    QueueOps,
1518 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
1519 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
1520 d0c8c01d Iustin Pop
  "watcher": (
1521 6ea815cf Iustin Pop
    WatcherOps,
1522 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
1523 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
1524 064c21f8 Iustin Pop
    [],
1525 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
1526 d0c8c01d Iustin Pop
  "modify": (
1527 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
1528 38f9d2cf Guido Trotter
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
1529 5a8648eb Andrea Spadaccini
     MASTER_NETMASK_OPT, NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT,
1530 5a8648eb Andrea Spadaccini
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT,
1531 5a8648eb Andrea Spadaccini
     DRBD_HELPER_OPT, NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT,
1532 5a8648eb Andrea Spadaccini
     RESERVED_LVS_OPT, DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT,
1533 2da9f556 René Nussbaumer
     NODE_PARAMS_OPT, USE_EXTERNAL_MIP_SCRIPT, DISK_PARAMS_OPT, HV_STATE_OPT,
1534 32017174 Agata Murawska
     DISK_STATE_OPT] +
1535 32017174 Agata Murawska
    INSTANCE_POLICY_OPTS,
1536 6ea815cf Iustin Pop
    "[opts...]",
1537 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
1538 6d4a1656 Michael Hanselmann
  "renew-crypto": (
1539 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
1540 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
1541 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
1542 b6267745 Andrea Spadaccini
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT,
1543 b6267745 Andrea Spadaccini
     NEW_SPICE_CERT_OPT, SPICE_CERT_OPT, SPICE_CACERT_OPT],
1544 6d4a1656 Michael Hanselmann
    "[opts...]",
1545 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
1546 66d1f035 René Nussbaumer
  "epo": (
1547 66d1f035 René Nussbaumer
    Epo, [ArgUnknown()],
1548 fcecea0b René Nussbaumer
    [FORCE_OPT, ON_OPT, GROUPS_OPT, ALL_OPT, OOB_TIMEOUT_OPT,
1549 cfed3b9f René Nussbaumer
     SHUTDOWN_TIMEOUT_OPT, POWER_DELAY_OPT],
1550 66d1f035 René Nussbaumer
    "[opts...] [args]",
1551 66d1f035 René Nussbaumer
    "Performs an emergency power-off on given args"),
1552 fb926117 Andrea Spadaccini
  "activate-master-ip": (
1553 fb926117 Andrea Spadaccini
    ActivateMasterIp, ARGS_NONE, [], "", "Activates the master IP"),
1554 fb926117 Andrea Spadaccini
  "deactivate-master-ip": (
1555 fb926117 Andrea Spadaccini
    DeactivateMasterIp, ARGS_NONE, [CONFIRM_OPT], "",
1556 fb926117 Andrea Spadaccini
    "Deactivates the master IP"),
1557 a8083063 Iustin Pop
  }
1558 a8083063 Iustin Pop
1559 6d4a1656 Michael Hanselmann
1560 c28502b1 Iustin Pop
#: dictionary with aliases for commands
1561 c28502b1 Iustin Pop
aliases = {
1562 d0c8c01d Iustin Pop
  "masterfailover": "master-failover",
1563 c28502b1 Iustin Pop
}
1564 c28502b1 Iustin Pop
1565 c28502b1 Iustin Pop
1566 7b3e7d41 Michael Hanselmann
def Main():
1567 7b3e7d41 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
1568 7b3e7d41 Michael Hanselmann
                     aliases=aliases)