Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 45f8b50d

History | View | Annotate | Download (50.9 kB)

1 7b3e7d41 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 c20a19ed Iustin Pop
# Copyright (C) 2006, 2007, 2010, 2011, 2012 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 5959f75d Agata Murawska
    objects.CreateIPolicyFromOpts(ispecs_mem_size=opts.ispecs_mem_size,
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 c4929a8b René Nussbaumer
  if opts.disk_state:
184 c4929a8b René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
185 c4929a8b René Nussbaumer
  else:
186 c4929a8b René Nussbaumer
    disk_state = {}
187 c4929a8b René Nussbaumer
188 c4929a8b René Nussbaumer
  hv_state = dict(opts.hv_state)
189 c4929a8b René Nussbaumer
190 a0c9f010 Michael Hanselmann
  bootstrap.InitCluster(cluster_name=args[0],
191 a0c9f010 Michael Hanselmann
                        secondary_ip=opts.secondary_ip,
192 a0c9f010 Michael Hanselmann
                        vg_name=vg_name,
193 a0c9f010 Michael Hanselmann
                        mac_prefix=opts.mac_prefix,
194 5a8648eb Andrea Spadaccini
                        master_netmask=master_netmask,
195 25be0c75 Guido Trotter
                        master_netdev=master_netdev,
196 ea3a925f Alexander Schreiber
                        file_storage_dir=opts.file_storage_dir,
197 7925d409 Apollon Oikonomopoulos
                        shared_file_storage_dir=opts.shared_file_storage_dir,
198 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
199 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
200 ce735215 Guido Trotter
                        beparams=beparams,
201 b6a30b0d Guido Trotter
                        nicparams=nicparams,
202 6204ee71 René Nussbaumer
                        ndparams=ndparams,
203 bc5d0215 Andrea Spadaccini
                        diskparams=diskparams,
204 18bb6d28 Agata Murawska
                        ipolicy=ipolicy,
205 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
206 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
207 b989b9d9 Ken Wehr
                        modify_ssh_setup=opts.modify_ssh_setup,
208 3953242f Iustin Pop
                        maintain_node_health=opts.maintain_node_health,
209 ed14ed48 Luca Bigliardi
                        drbd_helper=drbd_helper,
210 39b0f0c2 Balazs Lecz
                        uid_pool=uid_pool,
211 bf4af505 Apollon Oikonomopoulos
                        default_iallocator=opts.default_iallocator,
212 e7323b5e Manuel Franceschini
                        primary_ip_version=primary_ip_version,
213 b18ecea2 René Nussbaumer
                        prealloc_wipe_disks=opts.prealloc_wipe_disks,
214 bf689b7a Andrea Spadaccini
                        use_external_mip_script=external_ip_setup_script,
215 c4929a8b René Nussbaumer
                        hv_state=hv_state,
216 c4929a8b René Nussbaumer
                        disk_state=disk_state,
217 ce735215 Guido Trotter
                        )
218 bc84ffa7 Iustin Pop
  op = opcodes.OpClusterPostInit()
219 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
220 a8083063 Iustin Pop
  return 0
221 a8083063 Iustin Pop
222 a8083063 Iustin Pop
223 4331f6cd Michael Hanselmann
@UsesRPC
224 a8083063 Iustin Pop
def DestroyCluster(opts, args):
225 a8083063 Iustin Pop
  """Destroy the cluster.
226 a8083063 Iustin Pop

227 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
228 469ee405 Iustin Pop
  @type args: list
229 469ee405 Iustin Pop
  @param args: should be an empty list
230 469ee405 Iustin Pop
  @rtype: int
231 469ee405 Iustin Pop
  @return: the desired exit code
232 098c0958 Michael Hanselmann

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

250 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
251 469ee405 Iustin Pop
  @type args: list
252 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
253 469ee405 Iustin Pop
  @rtype: int
254 469ee405 Iustin Pop
  @return: the desired exit code
255 07bd8a51 Iustin Pop

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

283 fb926117 Andrea Spadaccini
  """
284 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
285 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
286 fb926117 Andrea Spadaccini
  return 0
287 fb926117 Andrea Spadaccini
288 fb926117 Andrea Spadaccini
289 fb926117 Andrea Spadaccini
def DeactivateMasterIp(opts, args):
290 fb926117 Andrea Spadaccini
  """Deactivates the master IP.
291 fb926117 Andrea Spadaccini

292 fb926117 Andrea Spadaccini
  """
293 fb926117 Andrea Spadaccini
  if not opts.confirm:
294 fb926117 Andrea Spadaccini
    usertext = ("This will disable the master IP. All the open connections to"
295 fb926117 Andrea Spadaccini
                " the master IP will be closed. To reach the master you will"
296 fb926117 Andrea Spadaccini
                " need to use its node IP."
297 fb926117 Andrea Spadaccini
                " Continue?")
298 fb926117 Andrea Spadaccini
    if not AskUser(usertext):
299 fb926117 Andrea Spadaccini
      return 1
300 fb926117 Andrea Spadaccini
301 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterDeactivateMasterIp()
302 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
303 fb926117 Andrea Spadaccini
  return 0
304 fb926117 Andrea Spadaccini
305 fb926117 Andrea Spadaccini
306 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
307 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
308 afee0879 Iustin Pop

309 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
310 afee0879 Iustin Pop
  @type args: list
311 afee0879 Iustin Pop
  @param args: empty list
312 afee0879 Iustin Pop
  @rtype: int
313 afee0879 Iustin Pop
  @return: the desired exit code
314 afee0879 Iustin Pop

315 afee0879 Iustin Pop
  """
316 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
317 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
318 afee0879 Iustin Pop
  return 0
319 afee0879 Iustin Pop
320 afee0879 Iustin Pop
321 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
322 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
323 a8083063 Iustin Pop

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

330 a8083063 Iustin Pop
  """
331 2e7b8369 Iustin Pop
  cl = GetClient()
332 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
333 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
334 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
335 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
336 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
337 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
338 a8083063 Iustin Pop
  return 0
339 a8083063 Iustin Pop
340 a8083063 Iustin Pop
341 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
342 a8083063 Iustin Pop
  """Write name of master node to the standard output.
343 a8083063 Iustin Pop

344 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
345 469ee405 Iustin Pop
  @type args: list
346 469ee405 Iustin Pop
  @param args: should be an empty list
347 469ee405 Iustin Pop
  @rtype: int
348 469ee405 Iustin Pop
  @return: the desired exit code
349 a8083063 Iustin Pop

350 a8083063 Iustin Pop
  """
351 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
352 8eb148ae Iustin Pop
  ToStdout(master)
353 a8083063 Iustin Pop
  return 0
354 a8083063 Iustin Pop
355 cac599f1 Michael Hanselmann
356 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
357 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
358 1094acda Guido Trotter

359 1094acda Guido Trotter
  @type paramsdict: dict of dicts
360 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
361 664a9d73 René Nussbaumer
  @type level: int
362 664a9d73 René Nussbaumer
  @param level: Level of indention
363 1094acda Guido Trotter

364 1094acda Guido Trotter
  """
365 664a9d73 René Nussbaumer
  indent = "  " * level
366 9d91c6ab Guido Trotter
  for item, val in sorted(paramsdict.items()):
367 664a9d73 René Nussbaumer
    if isinstance(val, dict):
368 664a9d73 René Nussbaumer
      ToStdout("%s- %s:", indent, item)
369 d729e03a Guido Trotter
      _PrintGroupedParams(val, level=level + 1, roman=roman)
370 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
371 d729e03a Guido Trotter
      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
372 664a9d73 René Nussbaumer
    else:
373 664a9d73 René Nussbaumer
      ToStdout("%s  %s: %s", indent, item, val)
374 a8083063 Iustin Pop
375 cac599f1 Michael Hanselmann
376 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
377 a8083063 Iustin Pop
  """Shows cluster information.
378 a8083063 Iustin Pop

379 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
380 469ee405 Iustin Pop
  @type args: list
381 469ee405 Iustin Pop
  @param args: should be an empty list
382 469ee405 Iustin Pop
  @rtype: int
383 469ee405 Iustin Pop
  @return: the desired exit code
384 469ee405 Iustin Pop

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

471 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
472 469ee405 Iustin Pop
  @type args: list
473 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
474 469ee405 Iustin Pop
      the file to be copied
475 469ee405 Iustin Pop
  @rtype: int
476 469ee405 Iustin Pop
  @return: the desired exit code
477 a8083063 Iustin Pop

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

503 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
504 469ee405 Iustin Pop
  @type args: list
505 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
506 469ee405 Iustin Pop
  @rtype: int
507 469ee405 Iustin Pop
  @return: the desired exit code
508 a8083063 Iustin Pop

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

539 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
540 469ee405 Iustin Pop
  @type args: list
541 469ee405 Iustin Pop
  @param args: should be an empty list
542 469ee405 Iustin Pop
  @rtype: int
543 469ee405 Iustin Pop
  @return: the desired exit code
544 a8083063 Iustin Pop

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

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

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

663 60975797 Iustin Pop
  @param opts: the command line options selected by the user
664 60975797 Iustin Pop
  @type args: list
665 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
666 60975797 Iustin Pop
  @rtype: int
667 60975797 Iustin Pop
  @return: the desired exit code
668 60975797 Iustin Pop

669 60975797 Iustin Pop
  """
670 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
671 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
672 60975797 Iustin Pop
673 60975797 Iustin Pop
674 4331f6cd Michael Hanselmann
@UsesRPC
675 a8083063 Iustin Pop
def MasterFailover(opts, args):
676 a8083063 Iustin Pop
  """Failover the master node.
677 a8083063 Iustin Pop

678 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
679 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
680 a8083063 Iustin Pop
  master.
681 a8083063 Iustin Pop

682 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
683 469ee405 Iustin Pop
  @type args: list
684 469ee405 Iustin Pop
  @param args: should be an empty list
685 469ee405 Iustin Pop
  @rtype: int
686 469ee405 Iustin Pop
  @return: the desired exit code
687 469ee405 Iustin Pop

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

703 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
704 4404ffad Iustin Pop
  @type args: list
705 4404ffad Iustin Pop
  @param args: should be an empty list
706 4404ffad Iustin Pop
  @rtype: int
707 4404ffad Iustin Pop
  @return: the desired exit code
708 4404ffad Iustin Pop

709 4404ffad Iustin Pop
  """
710 4404ffad Iustin Pop
  try:
711 4404ffad Iustin Pop
    cl = GetClient()
712 4404ffad Iustin Pop
    cl.QueryClusterInfo()
713 4404ffad Iustin Pop
    return 0
714 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
715 4404ffad Iustin Pop
    return 1
716 4404ffad Iustin Pop
717 4404ffad Iustin Pop
718 73415719 Iustin Pop
def SearchTags(opts, args):
719 73415719 Iustin Pop
  """Searches the tags on all the cluster.
720 73415719 Iustin Pop

721 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
722 469ee405 Iustin Pop
  @type args: list
723 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
724 469ee405 Iustin Pop
  @rtype: int
725 469ee405 Iustin Pop
  @return: the desired exit code
726 469ee405 Iustin Pop

727 73415719 Iustin Pop
  """
728 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
729 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
730 73415719 Iustin Pop
  if not result:
731 73415719 Iustin Pop
    return 1
732 73415719 Iustin Pop
  result = list(result)
733 73415719 Iustin Pop
  result.sort()
734 73415719 Iustin Pop
  for path, tag in result:
735 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
736 73415719 Iustin Pop
737 73415719 Iustin Pop
738 b6267745 Andrea Spadaccini
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
739 b6267745 Andrea Spadaccini
  """Reads and verifies an X509 certificate.
740 b6267745 Andrea Spadaccini

741 b6267745 Andrea Spadaccini
  @type cert_filename: string
742 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
743 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
744 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
745 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
746 b6267745 Andrea Spadaccini
                             the public certificate
747 b6267745 Andrea Spadaccini
  @rtype: string
748 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
749 b6267745 Andrea Spadaccini

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

779 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
780 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
781 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
782 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
783 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
784 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
785 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
786 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
787 b6267745 Andrea Spadaccini
  @type spice_cert_filename: string
788 b6267745 Andrea Spadaccini
  @param spice_cert_filename: Path to file containing new SPICE certificate
789 b6267745 Andrea Spadaccini
  @type spice_cacert_filename: string
790 b6267745 Andrea Spadaccini
  @param spice_cacert_filename: Path to file containing the certificate of the
791 b6267745 Andrea Spadaccini
                                CA that signed the SPICE certificate
792 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
793 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
794 3db3eb2a Michael Hanselmann
  @type new_cds: bool
795 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
796 3db3eb2a Michael Hanselmann
  @type cds_filename: string
797 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
798 6d4a1656 Michael Hanselmann
  @type force: bool
799 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
800 6d4a1656 Michael Hanselmann

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

898 6d4a1656 Michael Hanselmann
  """
899 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
900 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
901 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
902 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
903 b6267745 Andrea Spadaccini
                      opts.spice_cert,
904 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
905 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
906 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
907 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
908 6d4a1656 Michael Hanselmann
                      opts.force)
909 6d4a1656 Michael Hanselmann
910 6d4a1656 Michael Hanselmann
911 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
912 90b6aa3a Manuel Franceschini
  """Modify the cluster.
913 90b6aa3a Manuel Franceschini

914 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
915 469ee405 Iustin Pop
  @type args: list
916 469ee405 Iustin Pop
  @param args: should be an empty list
917 469ee405 Iustin Pop
  @rtype: int
918 469ee405 Iustin Pop
  @return: the desired exit code
919 90b6aa3a Manuel Franceschini

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

1061 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1062 469ee405 Iustin Pop
  @type args: list
1063 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1064 469ee405 Iustin Pop
  @rtype: int
1065 469ee405 Iustin Pop
  @return: the desired exit code
1066 469ee405 Iustin Pop

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

1097 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1098 95b2e626 Michael Hanselmann
  @type args: list
1099 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1100 95b2e626 Michael Hanselmann
  @rtype: int
1101 95b2e626 Michael Hanselmann
  @return: the desired exit code
1102 95b2e626 Michael Hanselmann

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

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

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

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

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

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

1209 66d1f035 René Nussbaumer
  """
1210 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1211 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1212 66d1f035 René Nussbaumer
    """Init the object.
1213 66d1f035 René Nussbaumer

1214 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1215 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1216 66d1f035 René Nussbaumer
    @type node2ip: dict
1217 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1218 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1219 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1220 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1221 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1222 66d1f035 René Nussbaumer

1223 66d1f035 René Nussbaumer
    """
1224 66d1f035 René Nussbaumer
    self.down = set(node_list)
1225 66d1f035 René Nussbaumer
    self.up = set()
1226 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1227 66d1f035 René Nussbaumer
    self.success = True
1228 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1229 66d1f035 René Nussbaumer
    self.port = port
1230 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1231 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1232 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1233 66d1f035 René Nussbaumer
1234 66d1f035 René Nussbaumer
  def __call__(self):
1235 66d1f035 René Nussbaumer
    """When called we run action_cb.
1236 66d1f035 René Nussbaumer

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

1239 66d1f035 René Nussbaumer
    """
1240 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1241 66d1f035 René Nussbaumer
      self.success = False
1242 66d1f035 René Nussbaumer
1243 66d1f035 René Nussbaumer
    if self.down:
1244 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1245 66d1f035 René Nussbaumer
    else:
1246 66d1f035 René Nussbaumer
      return self.success
1247 66d1f035 René Nussbaumer
1248 66d1f035 René Nussbaumer
  def Wait(self, secs):
1249 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1250 66d1f035 René Nussbaumer

1251 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1252 66d1f035 René Nussbaumer

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

1271 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1272 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1273 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1274 66d1f035 René Nussbaumer

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

1303 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1304 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1305 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1306 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1307 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1308 66d1f035 René Nussbaumer

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

1328 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1329 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1330 66d1f035 René Nussbaumer
                         OOB)
1331 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1332 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1333 66d1f035 René Nussbaumer
  @return: The desired exit status
1334 66d1f035 René Nussbaumer

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

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

1359 66d1f035 René Nussbaumer
  """
1360 66d1f035 René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False):
1361 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1362 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1363 66d1f035 René Nussbaumer
1364 66d1f035 René Nussbaumer
  if not node_list:
1365 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1366 66d1f035 René Nussbaumer
1367 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1368 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1369 66d1f035 René Nussbaumer
  else:
1370 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1371 66d1f035 René Nussbaumer
1372 66d1f035 René Nussbaumer
1373 66d1f035 René Nussbaumer
def Epo(opts, args):
1374 66d1f035 René Nussbaumer
  """EPO operations.
1375 66d1f035 René Nussbaumer

1376 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1377 66d1f035 René Nussbaumer
  @type args: list
1378 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1379 66d1f035 René Nussbaumer
  @rtype: int
1380 66d1f035 René Nussbaumer
  @return: the desired exit code
1381 66d1f035 René Nussbaumer

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