Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 57dc299a

History | View | Annotate | Download (51.2 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1066 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1067 469ee405 Iustin Pop
  @type args: list
1068 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1069 469ee405 Iustin Pop
  @rtype: int
1070 469ee405 Iustin Pop
  @return: the desired exit code
1071 469ee405 Iustin Pop

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

1102 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1103 95b2e626 Michael Hanselmann
  @type args: list
1104 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1105 95b2e626 Michael Hanselmann
  @rtype: int
1106 95b2e626 Michael Hanselmann
  @return: the desired exit code
1107 95b2e626 Michael Hanselmann

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

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

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

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

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

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

1214 66d1f035 René Nussbaumer
  """
1215 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1216 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1217 66d1f035 René Nussbaumer
    """Init the object.
1218 66d1f035 René Nussbaumer

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

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

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

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

1256 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1257 66d1f035 René Nussbaumer

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

1276 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1277 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1278 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1279 66d1f035 René Nussbaumer

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

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

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

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

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

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

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

1381 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1382 66d1f035 René Nussbaumer
  @type args: list
1383 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1384 66d1f035 René Nussbaumer
  @rtype: int
1385 66d1f035 René Nussbaumer
  @return: the desired exit code
1386 66d1f035 René Nussbaumer

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