Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 31d827d1

History | View | Annotate | Download (51.8 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 a24aed2a Michael Hanselmann
SHOW_MACHINE_OPT = cli_option("-M", "--show-machine-names", default=False,
56 a24aed2a Michael Hanselmann
                              action="store_true",
57 a24aed2a Michael Hanselmann
                              help="Show machine name for every line in output")
58 a24aed2a Michael Hanselmann
59 66d1f035 René Nussbaumer
_EPO_PING_INTERVAL = 30 # 30 seconds between pings
60 66d1f035 René Nussbaumer
_EPO_PING_TIMEOUT = 1 # 1 second
61 66d1f035 René Nussbaumer
_EPO_REACHABLE_TIMEOUT = 15 * 60 # 15 minutes
62 a8083063 Iustin Pop
63 a8083063 Iustin Pop
64 4331f6cd Michael Hanselmann
@UsesRPC
65 a8083063 Iustin Pop
def InitCluster(opts, args):
66 a8083063 Iustin Pop
  """Initialize the cluster.
67 a8083063 Iustin Pop

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

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

233 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
234 469ee405 Iustin Pop
  @type args: list
235 469ee405 Iustin Pop
  @param args: should be an empty list
236 469ee405 Iustin Pop
  @rtype: int
237 469ee405 Iustin Pop
  @return: the desired exit code
238 098c0958 Michael Hanselmann

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

256 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
257 469ee405 Iustin Pop
  @type args: list
258 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
259 469ee405 Iustin Pop
  @rtype: int
260 469ee405 Iustin Pop
  @return: the desired exit code
261 07bd8a51 Iustin Pop

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

289 fb926117 Andrea Spadaccini
  """
290 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
291 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
292 fb926117 Andrea Spadaccini
  return 0
293 fb926117 Andrea Spadaccini
294 fb926117 Andrea Spadaccini
295 fb926117 Andrea Spadaccini
def DeactivateMasterIp(opts, args):
296 fb926117 Andrea Spadaccini
  """Deactivates the master IP.
297 fb926117 Andrea Spadaccini

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

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

321 afee0879 Iustin Pop
  """
322 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
323 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
324 afee0879 Iustin Pop
  return 0
325 afee0879 Iustin Pop
326 afee0879 Iustin Pop
327 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
328 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
329 a8083063 Iustin Pop

330 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
331 469ee405 Iustin Pop
  @type args: list
332 469ee405 Iustin Pop
  @param args: should be an empty list
333 469ee405 Iustin Pop
  @rtype: int
334 469ee405 Iustin Pop
  @return: the desired exit code
335 a8083063 Iustin Pop

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

350 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
351 469ee405 Iustin Pop
  @type args: list
352 469ee405 Iustin Pop
  @param args: should be an empty list
353 469ee405 Iustin Pop
  @rtype: int
354 469ee405 Iustin Pop
  @return: the desired exit code
355 a8083063 Iustin Pop

356 a8083063 Iustin Pop
  """
357 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
358 8eb148ae Iustin Pop
  ToStdout(master)
359 a8083063 Iustin Pop
  return 0
360 a8083063 Iustin Pop
361 cac599f1 Michael Hanselmann
362 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
363 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
364 1094acda Guido Trotter

365 1094acda Guido Trotter
  @type paramsdict: dict of dicts
366 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
367 664a9d73 René Nussbaumer
  @type level: int
368 664a9d73 René Nussbaumer
  @param level: Level of indention
369 1094acda Guido Trotter

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

385 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
386 469ee405 Iustin Pop
  @type args: list
387 469ee405 Iustin Pop
  @param args: should be an empty list
388 469ee405 Iustin Pop
  @rtype: int
389 469ee405 Iustin Pop
  @return: the desired exit code
390 469ee405 Iustin Pop

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

484 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
485 469ee405 Iustin Pop
  @type args: list
486 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
487 469ee405 Iustin Pop
      the file to be copied
488 469ee405 Iustin Pop
  @rtype: int
489 469ee405 Iustin Pop
  @return: the desired exit code
490 a8083063 Iustin Pop

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

516 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
517 469ee405 Iustin Pop
  @type args: list
518 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
519 469ee405 Iustin Pop
  @rtype: int
520 469ee405 Iustin Pop
  @return: the desired exit code
521 a8083063 Iustin Pop

522 a8083063 Iustin Pop
  """
523 56bece1f Iustin Pop
  cl = GetClient()
524 7688d0d3 Michael Hanselmann
525 a8083063 Iustin Pop
  command = " ".join(args)
526 4040a784 Iustin Pop
527 b6e88032 Michael Hanselmann
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl, nodegroup=opts.nodegroup)
528 56bece1f Iustin Pop
529 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
530 56bece1f Iustin Pop
                                                    "master_node"])
531 b3989551 Iustin Pop
532 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
533 b3989551 Iustin Pop
534 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
535 b3989551 Iustin Pop
  if master_node in nodes:
536 b3989551 Iustin Pop
    nodes.remove(master_node)
537 b3989551 Iustin Pop
    nodes.append(master_node)
538 b3989551 Iustin Pop
539 b3989551 Iustin Pop
  for name in nodes:
540 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
541 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
542 a24aed2a Michael Hanselmann
    if opts.show_machine_names:
543 a24aed2a Michael Hanselmann
      for line in result.output.splitlines():
544 a24aed2a Michael Hanselmann
        ToStdout("%s: %s", name, line)
545 a24aed2a Michael Hanselmann
    else:
546 a24aed2a Michael Hanselmann
      ToStdout("node: %s", name)
547 a24aed2a Michael Hanselmann
      ToStdout("%s", result.output)
548 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
549 b3989551 Iustin Pop
550 b3989551 Iustin Pop
  return 0
551 a8083063 Iustin Pop
552 a8083063 Iustin Pop
553 a8083063 Iustin Pop
def VerifyCluster(opts, args):
554 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
555 a8083063 Iustin Pop

556 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
557 469ee405 Iustin Pop
  @type args: list
558 469ee405 Iustin Pop
  @param args: should be an empty list
559 469ee405 Iustin Pop
  @rtype: int
560 469ee405 Iustin Pop
  @return: the desired exit code
561 a8083063 Iustin Pop

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

609 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
610 469ee405 Iustin Pop
  @type args: list
611 469ee405 Iustin Pop
  @param args: should be an empty list
612 469ee405 Iustin Pop
  @rtype: int
613 469ee405 Iustin Pop
  @return: the desired exit code
614 f4d4e184 Iustin Pop

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

680 60975797 Iustin Pop
  @param opts: the command line options selected by the user
681 60975797 Iustin Pop
  @type args: list
682 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
683 60975797 Iustin Pop
  @rtype: int
684 60975797 Iustin Pop
  @return: the desired exit code
685 60975797 Iustin Pop

686 60975797 Iustin Pop
  """
687 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
688 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
689 60975797 Iustin Pop
690 60975797 Iustin Pop
691 4331f6cd Michael Hanselmann
@UsesRPC
692 a8083063 Iustin Pop
def MasterFailover(opts, args):
693 a8083063 Iustin Pop
  """Failover the master node.
694 a8083063 Iustin Pop

695 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
696 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
697 a8083063 Iustin Pop
  master.
698 a8083063 Iustin Pop

699 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
700 469ee405 Iustin Pop
  @type args: list
701 469ee405 Iustin Pop
  @param args: should be an empty list
702 469ee405 Iustin Pop
  @rtype: int
703 469ee405 Iustin Pop
  @return: the desired exit code
704 469ee405 Iustin Pop

705 a8083063 Iustin Pop
  """
706 8e2524c3 Guido Trotter
  if opts.no_voting:
707 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
708 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
709 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
710 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
711 8e2524c3 Guido Trotter
    if not AskUser(usertext):
712 8e2524c3 Guido Trotter
      return 1
713 8e2524c3 Guido Trotter
714 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
715 a8083063 Iustin Pop
716 a8083063 Iustin Pop
717 4404ffad Iustin Pop
def MasterPing(opts, args):
718 4404ffad Iustin Pop
  """Checks if the master is alive.
719 4404ffad Iustin Pop

720 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
721 4404ffad Iustin Pop
  @type args: list
722 4404ffad Iustin Pop
  @param args: should be an empty list
723 4404ffad Iustin Pop
  @rtype: int
724 4404ffad Iustin Pop
  @return: the desired exit code
725 4404ffad Iustin Pop

726 4404ffad Iustin Pop
  """
727 4404ffad Iustin Pop
  try:
728 4404ffad Iustin Pop
    cl = GetClient()
729 4404ffad Iustin Pop
    cl.QueryClusterInfo()
730 4404ffad Iustin Pop
    return 0
731 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
732 4404ffad Iustin Pop
    return 1
733 4404ffad Iustin Pop
734 4404ffad Iustin Pop
735 73415719 Iustin Pop
def SearchTags(opts, args):
736 73415719 Iustin Pop
  """Searches the tags on all the cluster.
737 73415719 Iustin Pop

738 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
739 469ee405 Iustin Pop
  @type args: list
740 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
741 469ee405 Iustin Pop
  @rtype: int
742 469ee405 Iustin Pop
  @return: the desired exit code
743 469ee405 Iustin Pop

744 73415719 Iustin Pop
  """
745 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
746 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
747 73415719 Iustin Pop
  if not result:
748 73415719 Iustin Pop
    return 1
749 73415719 Iustin Pop
  result = list(result)
750 73415719 Iustin Pop
  result.sort()
751 73415719 Iustin Pop
  for path, tag in result:
752 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
753 73415719 Iustin Pop
754 73415719 Iustin Pop
755 b6267745 Andrea Spadaccini
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
756 b6267745 Andrea Spadaccini
  """Reads and verifies an X509 certificate.
757 b6267745 Andrea Spadaccini

758 b6267745 Andrea Spadaccini
  @type cert_filename: string
759 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
760 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
761 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
762 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
763 b6267745 Andrea Spadaccini
                             the public certificate
764 b6267745 Andrea Spadaccini
  @rtype: string
765 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
766 b6267745 Andrea Spadaccini

767 b6267745 Andrea Spadaccini
  """
768 b6267745 Andrea Spadaccini
  try:
769 b6267745 Andrea Spadaccini
    pem = utils.ReadFile(cert_filename)
770 b6267745 Andrea Spadaccini
  except IOError, err:
771 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
772 b6267745 Andrea Spadaccini
                               "Unable to read certificate: %s" % str(err))
773 b6267745 Andrea Spadaccini
774 b6267745 Andrea Spadaccini
  try:
775 b6267745 Andrea Spadaccini
    OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
776 b6267745 Andrea Spadaccini
  except Exception, err:
777 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
778 b6267745 Andrea Spadaccini
                               "Unable to load certificate: %s" % str(err))
779 b6267745 Andrea Spadaccini
780 b6267745 Andrea Spadaccini
  if verify_private_key:
781 b6267745 Andrea Spadaccini
    try:
782 b6267745 Andrea Spadaccini
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, pem)
783 b6267745 Andrea Spadaccini
    except Exception, err:
784 b6267745 Andrea Spadaccini
      raise errors.X509CertError(cert_filename,
785 b6267745 Andrea Spadaccini
                                 "Unable to load private key: %s" % str(err))
786 b6267745 Andrea Spadaccini
787 b6267745 Andrea Spadaccini
  return pem
788 b6267745 Andrea Spadaccini
789 b6267745 Andrea Spadaccini
790 b6267745 Andrea Spadaccini
def _RenewCrypto(new_cluster_cert, new_rapi_cert, #pylint: disable=R0911
791 b6267745 Andrea Spadaccini
                 rapi_cert_filename, new_spice_cert, spice_cert_filename,
792 b6267745 Andrea Spadaccini
                 spice_cacert_filename, new_confd_hmac_key, new_cds,
793 b6267745 Andrea Spadaccini
                 cds_filename, force):
794 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
795 6d4a1656 Michael Hanselmann

796 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
797 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
798 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
799 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
800 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
801 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
802 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
803 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
804 b6267745 Andrea Spadaccini
  @type spice_cert_filename: string
805 b6267745 Andrea Spadaccini
  @param spice_cert_filename: Path to file containing new SPICE certificate
806 b6267745 Andrea Spadaccini
  @type spice_cacert_filename: string
807 b6267745 Andrea Spadaccini
  @param spice_cacert_filename: Path to file containing the certificate of the
808 b6267745 Andrea Spadaccini
                                CA that signed the SPICE certificate
809 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
810 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
811 3db3eb2a Michael Hanselmann
  @type new_cds: bool
812 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
813 3db3eb2a Michael Hanselmann
  @type cds_filename: string
814 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
815 6d4a1656 Michael Hanselmann
  @type force: bool
816 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
817 6d4a1656 Michael Hanselmann

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

915 6d4a1656 Michael Hanselmann
  """
916 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
917 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
918 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
919 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
920 b6267745 Andrea Spadaccini
                      opts.spice_cert,
921 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
922 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
923 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
924 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
925 6d4a1656 Michael Hanselmann
                      opts.force)
926 6d4a1656 Michael Hanselmann
927 6d4a1656 Michael Hanselmann
928 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
929 90b6aa3a Manuel Franceschini
  """Modify the cluster.
930 90b6aa3a Manuel Franceschini

931 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
932 469ee405 Iustin Pop
  @type args: list
933 469ee405 Iustin Pop
  @param args: should be an empty list
934 469ee405 Iustin Pop
  @rtype: int
935 469ee405 Iustin Pop
  @return: the desired exit code
936 90b6aa3a Manuel Franceschini

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

1085 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1086 469ee405 Iustin Pop
  @type args: list
1087 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1088 469ee405 Iustin Pop
  @rtype: int
1089 469ee405 Iustin Pop
  @return: the desired exit code
1090 469ee405 Iustin Pop

1091 3ccafd0e Iustin Pop
  """
1092 3ccafd0e Iustin Pop
  command = args[0]
1093 3ccafd0e Iustin Pop
  client = GetClient()
1094 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
1095 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
1096 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
1097 3ccafd0e Iustin Pop
  elif command == "info":
1098 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
1099 3ccafd0e Iustin Pop
    if result[0]:
1100 3a24c527 Iustin Pop
      val = "set"
1101 3ccafd0e Iustin Pop
    else:
1102 3a24c527 Iustin Pop
      val = "unset"
1103 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
1104 2e668b38 Guido Trotter
  else:
1105 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1106 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1107 2e668b38 Guido Trotter
1108 3ccafd0e Iustin Pop
  return 0
1109 3ccafd0e Iustin Pop
1110 95b2e626 Michael Hanselmann
1111 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
1112 28b498cd Michael Hanselmann
  if until is None or until < time.time():
1113 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
1114 28b498cd Michael Hanselmann
  else:
1115 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
1116 28b498cd Michael Hanselmann
1117 28b498cd Michael Hanselmann
1118 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
1119 95b2e626 Michael Hanselmann
  """Watcher operations.
1120 95b2e626 Michael Hanselmann

1121 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1122 95b2e626 Michael Hanselmann
  @type args: list
1123 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1124 95b2e626 Michael Hanselmann
  @rtype: int
1125 95b2e626 Michael Hanselmann
  @return: the desired exit code
1126 95b2e626 Michael Hanselmann

1127 95b2e626 Michael Hanselmann
  """
1128 95b2e626 Michael Hanselmann
  command = args[0]
1129 95b2e626 Michael Hanselmann
  client = GetClient()
1130 95b2e626 Michael Hanselmann
1131 95b2e626 Michael Hanselmann
  if command == "continue":
1132 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
1133 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
1134 95b2e626 Michael Hanselmann
1135 95b2e626 Michael Hanselmann
  elif command == "pause":
1136 95b2e626 Michael Hanselmann
    if len(args) < 2:
1137 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
1138 95b2e626 Michael Hanselmann
1139 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
1140 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
1141 95b2e626 Michael Hanselmann
1142 95b2e626 Michael Hanselmann
  elif command == "info":
1143 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
1144 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
1145 95b2e626 Michael Hanselmann
1146 95b2e626 Michael Hanselmann
  else:
1147 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1148 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1149 95b2e626 Michael Hanselmann
1150 95b2e626 Michael Hanselmann
  return 0
1151 95b2e626 Michael Hanselmann
1152 95b2e626 Michael Hanselmann
1153 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
1154 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
1155 66d1f035 René Nussbaumer

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

1161 66d1f035 René Nussbaumer
  """
1162 66d1f035 René Nussbaumer
  if power:
1163 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
1164 66d1f035 René Nussbaumer
  else:
1165 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
1166 66d1f035 René Nussbaumer
1167 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
1168 66d1f035 René Nussbaumer
                            command=command,
1169 66d1f035 René Nussbaumer
                            ignore_status=True,
1170 cfed3b9f René Nussbaumer
                            timeout=opts.oob_timeout,
1171 cfed3b9f René Nussbaumer
                            power_delay=opts.power_delay)
1172 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
1173 66d1f035 René Nussbaumer
  errs = 0
1174 66d1f035 René Nussbaumer
  for node_result in result:
1175 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
1176 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
1177 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
1178 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
1179 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
1180 66d1f035 René Nussbaumer
      errs += 1
1181 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
1182 66d1f035 René Nussbaumer
               node_name)
1183 66d1f035 René Nussbaumer
1184 66d1f035 René Nussbaumer
  if errs > 0:
1185 66d1f035 René Nussbaumer
    return False
1186 66d1f035 René Nussbaumer
1187 66d1f035 René Nussbaumer
  return True
1188 66d1f035 René Nussbaumer
1189 66d1f035 René Nussbaumer
1190 3e0ed18c René Nussbaumer
def _InstanceStart(opts, inst_list, start, no_remember=False):
1191 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
1192 66d1f035 René Nussbaumer

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

1199 66d1f035 René Nussbaumer
  """
1200 66d1f035 René Nussbaumer
  if start:
1201 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
1202 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
1203 66d1f035 René Nussbaumer
  else:
1204 fcecea0b René Nussbaumer
    opcls = compat.partial(opcodes.OpInstanceShutdown,
1205 3e0ed18c René Nussbaumer
                           timeout=opts.shutdown_timeout,
1206 3e0ed18c René Nussbaumer
                           no_remember=no_remember)
1207 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
1208 66d1f035 René Nussbaumer
1209 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
1210 66d1f035 René Nussbaumer
1211 66d1f035 René Nussbaumer
  for inst in inst_list:
1212 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
1213 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
1214 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
1215 66d1f035 René Nussbaumer
1216 66d1f035 René Nussbaumer
  results = jex.GetResults()
1217 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
1218 66d1f035 René Nussbaumer
1219 66d1f035 René Nussbaumer
  if bad_cnt == 0:
1220 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
1221 66d1f035 René Nussbaumer
  else:
1222 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
1223 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
1224 66d1f035 René Nussbaumer
             len(results))
1225 66d1f035 René Nussbaumer
    return False
1226 66d1f035 René Nussbaumer
1227 66d1f035 René Nussbaumer
  return True
1228 66d1f035 René Nussbaumer
1229 66d1f035 René Nussbaumer
1230 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
1231 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
1232 66d1f035 René Nussbaumer

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

1235 66d1f035 René Nussbaumer
  """
1236 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1237 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1238 66d1f035 René Nussbaumer
    """Init the object.
1239 66d1f035 René Nussbaumer

1240 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1241 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1242 66d1f035 René Nussbaumer
    @type node2ip: dict
1243 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1244 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1245 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1246 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1247 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1248 66d1f035 René Nussbaumer

1249 66d1f035 René Nussbaumer
    """
1250 66d1f035 René Nussbaumer
    self.down = set(node_list)
1251 66d1f035 René Nussbaumer
    self.up = set()
1252 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1253 66d1f035 René Nussbaumer
    self.success = True
1254 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1255 66d1f035 René Nussbaumer
    self.port = port
1256 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1257 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1258 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1259 66d1f035 René Nussbaumer
1260 66d1f035 René Nussbaumer
  def __call__(self):
1261 66d1f035 René Nussbaumer
    """When called we run action_cb.
1262 66d1f035 René Nussbaumer

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

1265 66d1f035 René Nussbaumer
    """
1266 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1267 66d1f035 René Nussbaumer
      self.success = False
1268 66d1f035 René Nussbaumer
1269 66d1f035 René Nussbaumer
    if self.down:
1270 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1271 66d1f035 René Nussbaumer
    else:
1272 66d1f035 René Nussbaumer
      return self.success
1273 66d1f035 René Nussbaumer
1274 66d1f035 René Nussbaumer
  def Wait(self, secs):
1275 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1276 66d1f035 René Nussbaumer

1277 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1278 66d1f035 René Nussbaumer

1279 66d1f035 René Nussbaumer
    """
1280 66d1f035 René Nussbaumer
    start = time.time()
1281 66d1f035 René Nussbaumer
    for node in self.down:
1282 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1283 66d1f035 René Nussbaumer
                       live_port_needed=True):
1284 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1285 66d1f035 René Nussbaumer
        self.up.add(node)
1286 66d1f035 René Nussbaumer
        self.down -= self.up
1287 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1288 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1289 66d1f035 René Nussbaumer
        return
1290 66d1f035 René Nussbaumer
1291 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1292 66d1f035 René Nussbaumer
1293 66d1f035 René Nussbaumer
1294 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1295 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1296 66d1f035 René Nussbaumer

1297 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1298 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1299 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1300 66d1f035 René Nussbaumer

1301 66d1f035 René Nussbaumer
  """
1302 66d1f035 René Nussbaumer
  client = GetClient()
1303 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1304 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1305 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1306 66d1f035 René Nussbaumer
  else:
1307 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1308 66d1f035 René Nussbaumer
1309 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1310 66d1f035 René Nussbaumer
                 for node in node_list)
1311 66d1f035 René Nussbaumer
1312 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1313 8e74adce René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port,
1314 8e74adce René Nussbaumer
                                        ToStdout)
1315 66d1f035 René Nussbaumer
1316 66d1f035 René Nussbaumer
  try:
1317 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1318 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1319 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1320 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1321 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1322 66d1f035 René Nussbaumer
    return False
1323 66d1f035 René Nussbaumer
1324 66d1f035 René Nussbaumer
1325 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1326 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1327 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1328 66d1f035 René Nussbaumer

1329 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1330 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1331 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1332 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1333 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1334 66d1f035 René Nussbaumer

1335 66d1f035 René Nussbaumer
  """
1336 66d1f035 René Nussbaumer
  start_inst_list = []
1337 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1338 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1339 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1340 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1341 66d1f035 René Nussbaumer
1342 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1343 66d1f035 René Nussbaumer
    del inst_map[inst]
1344 66d1f035 René Nussbaumer
1345 66d1f035 René Nussbaumer
  if start_inst_list:
1346 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1347 66d1f035 René Nussbaumer
1348 66d1f035 René Nussbaumer
  return True
1349 66d1f035 René Nussbaumer
1350 66d1f035 René Nussbaumer
1351 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1352 66d1f035 René Nussbaumer
  """Does the actual power on.
1353 66d1f035 René Nussbaumer

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

1361 66d1f035 René Nussbaumer
  """
1362 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1363 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1364 66d1f035 René Nussbaumer
             " manually if needed")
1365 66d1f035 René Nussbaumer
1366 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1367 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1368 66d1f035 René Nussbaumer
1369 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1370 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1371 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1372 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1373 66d1f035 René Nussbaumer
1374 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1375 66d1f035 René Nussbaumer
1376 66d1f035 René Nussbaumer
1377 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1378 66d1f035 René Nussbaumer
  """Does the actual power off.
1379 66d1f035 René Nussbaumer

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

1385 66d1f035 René Nussbaumer
  """
1386 3e0ed18c René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False, no_remember=True):
1387 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1388 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1389 66d1f035 René Nussbaumer
1390 66d1f035 René Nussbaumer
  if not node_list:
1391 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1392 66d1f035 René Nussbaumer
1393 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1394 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1395 66d1f035 René Nussbaumer
  else:
1396 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1397 66d1f035 René Nussbaumer
1398 66d1f035 René Nussbaumer
1399 66d1f035 René Nussbaumer
def Epo(opts, args):
1400 66d1f035 René Nussbaumer
  """EPO operations.
1401 66d1f035 René Nussbaumer

1402 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1403 66d1f035 René Nussbaumer
  @type args: list
1404 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1405 66d1f035 René Nussbaumer
  @rtype: int
1406 66d1f035 René Nussbaumer
  @return: the desired exit code
1407 66d1f035 René Nussbaumer

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