Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 0cffcdb1

History | View | Annotate | Download (71.2 kB)

1 7b3e7d41 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 8a5d326f Jose A. Lopes
# Copyright (C) 2006, 2007, 2010, 2011, 2012, 2013, 2014 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 ea9d3b40 Bernardo Dal Seno
from cStringIO import StringIO
30 3b31c9da Klaus Aehlig
import os
31 95b2e626 Michael Hanselmann
import time
32 6d4a1656 Michael Hanselmann
import OpenSSL
33 66d1f035 René Nussbaumer
import itertools
34 a8083063 Iustin Pop
35 a8083063 Iustin Pop
from ganeti.cli import *
36 a0c9f010 Michael Hanselmann
from ganeti import bootstrap
37 cea881e5 Michael Hanselmann
from ganeti import compat
38 0fcb3314 Jose A. Lopes
from ganeti import constants
39 0fcb3314 Jose A. Lopes
from ganeti import errors
40 66d1f035 René Nussbaumer
from ganeti import netutils
41 0fcb3314 Jose A. Lopes
from ganeti import objects
42 0fcb3314 Jose A. Lopes
from ganeti import opcodes
43 78e706bb Michael Hanselmann
from ganeti import pathutils
44 c51ffffe Klaus Aehlig
from ganeti import qlang
45 0fcb3314 Jose A. Lopes
from ganeti import serializer
46 0fcb3314 Jose A. Lopes
from ganeti import ssconf
47 0fcb3314 Jose A. Lopes
from ganeti import ssh
48 0fcb3314 Jose A. Lopes
from ganeti import uidpool
49 0fcb3314 Jose A. Lopes
from ganeti import utils
50 0fcb3314 Jose A. Lopes
from ganeti.client import base
51 66d1f035 René Nussbaumer
52 66d1f035 René Nussbaumer
53 66d1f035 René Nussbaumer
ON_OPT = cli_option("--on", default=False,
54 66d1f035 René Nussbaumer
                    action="store_true", dest="on",
55 66d1f035 René Nussbaumer
                    help="Recover from an EPO")
56 66d1f035 René Nussbaumer
57 66d1f035 René Nussbaumer
GROUPS_OPT = cli_option("--groups", default=False,
58 5ae4945a Iustin Pop
                        action="store_true", dest="groups",
59 5ae4945a Iustin Pop
                        help="Arguments are node groups instead of nodes")
60 66d1f035 René Nussbaumer
61 6022a419 Iustin Pop
FORCE_FAILOVER = cli_option("--yes-do-it", dest="yes_do_it",
62 6022a419 Iustin Pop
                            help="Override interactive check for --no-voting",
63 6022a419 Iustin Pop
                            default=False, action="store_true")
64 6022a419 Iustin Pop
65 0c455e40 Klaus Aehlig
FORCE_DISTRIBUTION = cli_option("--yes-do-it", dest="yes_do_it",
66 0c455e40 Klaus Aehlig
                                help="Unconditionally distribute the"
67 0c455e40 Klaus Aehlig
                                " configuration, even if the queue"
68 0c455e40 Klaus Aehlig
                                " is drained",
69 0c455e40 Klaus Aehlig
                                default=False, action="store_true")
70 0c455e40 Klaus Aehlig
71 c51ffffe Klaus Aehlig
TO_OPT = cli_option("--to", default=None, type="string",
72 c51ffffe Klaus Aehlig
                    help="The Ganeti version to upgrade to")
73 c51ffffe Klaus Aehlig
74 c51ffffe Klaus Aehlig
RESUME_OPT = cli_option("--resume", default=False, action="store_true",
75 c51ffffe Klaus Aehlig
                        help="Resume any pending Ganeti upgrades")
76 c51ffffe Klaus Aehlig
77 66d1f035 René Nussbaumer
_EPO_PING_INTERVAL = 30 # 30 seconds between pings
78 66d1f035 René Nussbaumer
_EPO_PING_TIMEOUT = 1 # 1 second
79 66d1f035 René Nussbaumer
_EPO_REACHABLE_TIMEOUT = 15 * 60 # 15 minutes
80 a8083063 Iustin Pop
81 a8083063 Iustin Pop
82 c121d42f Helga Velroyen
def _InitEnabledDiskTemplates(opts):
83 c121d42f Helga Velroyen
  """Initialize the list of enabled disk templates.
84 c121d42f Helga Velroyen

85 c121d42f Helga Velroyen
  """
86 c121d42f Helga Velroyen
  if opts.enabled_disk_templates:
87 c121d42f Helga Velroyen
    return opts.enabled_disk_templates.split(",")
88 c121d42f Helga Velroyen
  else:
89 c121d42f Helga Velroyen
    return constants.DEFAULT_ENABLED_DISK_TEMPLATES
90 c121d42f Helga Velroyen
91 c121d42f Helga Velroyen
92 c121d42f Helga Velroyen
def _InitVgName(opts, enabled_disk_templates):
93 c121d42f Helga Velroyen
  """Initialize the volume group name.
94 c121d42f Helga Velroyen

95 c121d42f Helga Velroyen
  @type enabled_disk_templates: list of strings
96 c121d42f Helga Velroyen
  @param enabled_disk_templates: cluster-wide enabled disk templates
97 c121d42f Helga Velroyen

98 c121d42f Helga Velroyen
  """
99 c121d42f Helga Velroyen
  vg_name = None
100 c121d42f Helga Velroyen
  if opts.vg_name is not None:
101 c121d42f Helga Velroyen
    vg_name = opts.vg_name
102 c121d42f Helga Velroyen
    if vg_name:
103 c121d42f Helga Velroyen
      if not utils.IsLvmEnabled(enabled_disk_templates):
104 c121d42f Helga Velroyen
        ToStdout("You specified a volume group with --vg-name, but you did not"
105 c121d42f Helga Velroyen
                 " enable any disk template that uses lvm.")
106 c121d42f Helga Velroyen
    elif utils.IsLvmEnabled(enabled_disk_templates):
107 c121d42f Helga Velroyen
      raise errors.OpPrereqError(
108 c121d42f Helga Velroyen
          "LVM disk templates are enabled, but vg name not set.")
109 c121d42f Helga Velroyen
  elif utils.IsLvmEnabled(enabled_disk_templates):
110 c121d42f Helga Velroyen
    vg_name = constants.DEFAULT_VG
111 c121d42f Helga Velroyen
  return vg_name
112 c121d42f Helga Velroyen
113 c121d42f Helga Velroyen
114 7796e1f8 Helga Velroyen
def _InitDrbdHelper(opts, enabled_disk_templates):
115 c121d42f Helga Velroyen
  """Initialize the DRBD usermode helper.
116 c121d42f Helga Velroyen

117 c121d42f Helga Velroyen
  """
118 7796e1f8 Helga Velroyen
  drbd_enabled = constants.DT_DRBD8 in enabled_disk_templates
119 7796e1f8 Helga Velroyen
120 38969795 Helga Velroyen
  if not drbd_enabled and opts.drbd_helper is not None:
121 38969795 Helga Velroyen
    ToStdout("Note: You specified a DRBD usermode helper, while DRBD storage"
122 38969795 Helga Velroyen
             " is not enabled.")
123 c121d42f Helga Velroyen
124 7796e1f8 Helga Velroyen
  if drbd_enabled:
125 7796e1f8 Helga Velroyen
    if opts.drbd_helper is None:
126 7796e1f8 Helga Velroyen
      return constants.DEFAULT_DRBD_HELPER
127 7796e1f8 Helga Velroyen
    if opts.drbd_helper == '':
128 7796e1f8 Helga Velroyen
      raise errors.OpPrereqError(
129 7796e1f8 Helga Velroyen
          "Unsetting the drbd usermode helper while enabling DRBD is not"
130 7796e1f8 Helga Velroyen
          " allowed.")
131 c121d42f Helga Velroyen
132 c121d42f Helga Velroyen
  return opts.drbd_helper
133 c121d42f Helga Velroyen
134 c121d42f Helga Velroyen
135 4331f6cd Michael Hanselmann
@UsesRPC
136 a8083063 Iustin Pop
def InitCluster(opts, args):
137 a8083063 Iustin Pop
  """Initialize the cluster.
138 a8083063 Iustin Pop

139 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
140 469ee405 Iustin Pop
  @type args: list
141 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
142 469ee405 Iustin Pop
      cluster name
143 469ee405 Iustin Pop
  @rtype: int
144 469ee405 Iustin Pop
  @return: the desired exit code
145 a8083063 Iustin Pop

146 a8083063 Iustin Pop
  """
147 c121d42f Helga Velroyen
  enabled_disk_templates = _InitEnabledDiskTemplates(opts)
148 90b6aa3a Manuel Franceschini
149 c121d42f Helga Velroyen
  try:
150 c121d42f Helga Velroyen
    vg_name = _InitVgName(opts, enabled_disk_templates)
151 7796e1f8 Helga Velroyen
    drbd_helper = _InitDrbdHelper(opts, enabled_disk_templates)
152 c121d42f Helga Velroyen
  except errors.OpPrereqError, e:
153 c121d42f Helga Velroyen
    ToStderr(str(e))
154 ed14ed48 Luca Bigliardi
    return 1
155 ed14ed48 Luca Bigliardi
156 25be0c75 Guido Trotter
  master_netdev = opts.master_netdev
157 25be0c75 Guido Trotter
  if master_netdev is None:
158 5ce6fa9a Sebastian Gebhard
    nic_mode = opts.nicparams.get(constants.NIC_MODE, None)
159 5ce6fa9a Sebastian Gebhard
    if not nic_mode:
160 90017904 Sebastian Gebhard
      # default case, use bridging
161 90017904 Sebastian Gebhard
      master_netdev = constants.DEFAULT_BRIDGE
162 5ce6fa9a Sebastian Gebhard
    elif nic_mode == constants.NIC_MODE_OVS:
163 90017904 Sebastian Gebhard
      # default ovs is different from default bridge
164 90017904 Sebastian Gebhard
      master_netdev = constants.DEFAULT_OVS
165 90017904 Sebastian Gebhard
      opts.nicparams[constants.NIC_LINK] = constants.DEFAULT_OVS
166 25be0c75 Guido Trotter
167 ea3a925f Alexander Schreiber
  hvlist = opts.enabled_hypervisors
168 383a3591 Iustin Pop
  if hvlist is None:
169 383a3591 Iustin Pop
    hvlist = constants.DEFAULT_ENABLED_HYPERVISOR
170 066f465d Guido Trotter
  hvlist = hvlist.split(",")
171 ea3a925f Alexander Schreiber
172 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
173 ea3a925f Alexander Schreiber
  beparams = opts.beparams
174 b6a30b0d Guido Trotter
  nicparams = opts.nicparams
175 ea3a925f Alexander Schreiber
176 bc5d0215 Andrea Spadaccini
  diskparams = dict(opts.diskparams)
177 bc5d0215 Andrea Spadaccini
178 bc5d0215 Andrea Spadaccini
  # check the disk template types here, as we cannot rely on the type check done
179 bc5d0215 Andrea Spadaccini
  # by the opcode parameter types
180 bc5d0215 Andrea Spadaccini
  diskparams_keys = set(diskparams.keys())
181 bc5d0215 Andrea Spadaccini
  if not (diskparams_keys <= constants.DISK_TEMPLATES):
182 bc5d0215 Andrea Spadaccini
    unknown = utils.NiceSort(diskparams_keys - constants.DISK_TEMPLATES)
183 bc5d0215 Andrea Spadaccini
    ToStderr("Disk templates unknown: %s" % utils.CommaJoin(unknown))
184 bc5d0215 Andrea Spadaccini
    return 1
185 bc5d0215 Andrea Spadaccini
186 ea3a925f Alexander Schreiber
  # prepare beparams dict
187 d3cfe525 Guido Trotter
  beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams)
188 b2e233a5 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT)
189 ea3a925f Alexander Schreiber
190 b6a30b0d Guido Trotter
  # prepare nicparams dict
191 b6a30b0d Guido Trotter
  nicparams = objects.FillDict(constants.NICC_DEFAULTS, nicparams)
192 b6a30b0d Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
193 b6a30b0d Guido Trotter
194 6204ee71 René Nussbaumer
  # prepare ndparams dict
195 6204ee71 René Nussbaumer
  if opts.ndparams is None:
196 6204ee71 René Nussbaumer
    ndparams = dict(constants.NDC_DEFAULTS)
197 6204ee71 René Nussbaumer
  else:
198 6204ee71 René Nussbaumer
    ndparams = objects.FillDict(constants.NDC_DEFAULTS, opts.ndparams)
199 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
200 6204ee71 René Nussbaumer
201 ea3a925f Alexander Schreiber
  # prepare hvparams dict
202 ea3a925f Alexander Schreiber
  for hv in constants.HYPER_TYPES:
203 ea3a925f Alexander Schreiber
    if hv not in hvparams:
204 ea3a925f Alexander Schreiber
      hvparams[hv] = {}
205 d3cfe525 Guido Trotter
    hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv])
206 a5728081 Guido Trotter
    utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES)
207 ea3a925f Alexander Schreiber
208 bc5d0215 Andrea Spadaccini
  # prepare diskparams dict
209 bc5d0215 Andrea Spadaccini
  for templ in constants.DISK_TEMPLATES:
210 bc5d0215 Andrea Spadaccini
    if templ not in diskparams:
211 bc5d0215 Andrea Spadaccini
      diskparams[templ] = {}
212 bc5d0215 Andrea Spadaccini
    diskparams[templ] = objects.FillDict(constants.DISK_DT_DEFAULTS[templ],
213 bc5d0215 Andrea Spadaccini
                                         diskparams[templ])
214 bc5d0215 Andrea Spadaccini
    utils.ForceDictType(diskparams[templ], constants.DISK_DT_TYPES)
215 bc5d0215 Andrea Spadaccini
216 18bb6d28 Agata Murawska
  # prepare ipolicy dict
217 eeaa5f6c Bernardo Dal Seno
  ipolicy = CreateIPolicyFromOpts(
218 976b78ba Iustin Pop
    ispecs_mem_size=opts.ispecs_mem_size,
219 976b78ba Iustin Pop
    ispecs_cpu_count=opts.ispecs_cpu_count,
220 976b78ba Iustin Pop
    ispecs_disk_count=opts.ispecs_disk_count,
221 976b78ba Iustin Pop
    ispecs_disk_size=opts.ispecs_disk_size,
222 976b78ba Iustin Pop
    ispecs_nic_count=opts.ispecs_nic_count,
223 d2d3935a Bernardo Dal Seno
    minmax_ispecs=opts.ipolicy_bounds_specs,
224 d2d3935a Bernardo Dal Seno
    std_ispecs=opts.ipolicy_std_specs,
225 976b78ba Iustin Pop
    ipolicy_disk_templates=opts.ipolicy_disk_templates,
226 976b78ba Iustin Pop
    ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio,
227 31d827d1 René Nussbaumer
    ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio,
228 976b78ba Iustin Pop
    fill_all=True)
229 18bb6d28 Agata Murawska
230 e32df528 Iustin Pop
  if opts.candidate_pool_size is None:
231 e32df528 Iustin Pop
    opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT
232 e32df528 Iustin Pop
233 e3646f22 Iustin Pop
  if opts.mac_prefix is None:
234 e3646f22 Iustin Pop
    opts.mac_prefix = constants.DEFAULT_MAC_PREFIX
235 e3646f22 Iustin Pop
236 39b0f0c2 Balazs Lecz
  uid_pool = opts.uid_pool
237 39b0f0c2 Balazs Lecz
  if uid_pool is not None:
238 39b0f0c2 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
239 39b0f0c2 Balazs Lecz
240 b883637f René Nussbaumer
  if opts.prealloc_wipe_disks is None:
241 b883637f René Nussbaumer
    opts.prealloc_wipe_disks = False
242 b883637f René Nussbaumer
243 bf689b7a Andrea Spadaccini
  external_ip_setup_script = opts.use_external_mip_script
244 bf689b7a Andrea Spadaccini
  if external_ip_setup_script is None:
245 bf689b7a Andrea Spadaccini
    external_ip_setup_script = False
246 bf689b7a Andrea Spadaccini
247 e7323b5e Manuel Franceschini
  try:
248 e7323b5e Manuel Franceschini
    primary_ip_version = int(opts.primary_ip_version)
249 e7323b5e Manuel Franceschini
  except (ValueError, TypeError), err:
250 e7323b5e Manuel Franceschini
    ToStderr("Invalid primary ip version value: %s" % str(err))
251 e7323b5e Manuel Franceschini
    return 1
252 e7323b5e Manuel Franceschini
253 5a8648eb Andrea Spadaccini
  master_netmask = opts.master_netmask
254 5a8648eb Andrea Spadaccini
  try:
255 5a8648eb Andrea Spadaccini
    if master_netmask is not None:
256 5a8648eb Andrea Spadaccini
      master_netmask = int(master_netmask)
257 5a8648eb Andrea Spadaccini
  except (ValueError, TypeError), err:
258 5a8648eb Andrea Spadaccini
    ToStderr("Invalid master netmask value: %s" % str(err))
259 5a8648eb Andrea Spadaccini
    return 1
260 5a8648eb Andrea Spadaccini
261 c4929a8b René Nussbaumer
  if opts.disk_state:
262 c4929a8b René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
263 c4929a8b René Nussbaumer
  else:
264 c4929a8b René Nussbaumer
    disk_state = {}
265 c4929a8b René Nussbaumer
266 c4929a8b René Nussbaumer
  hv_state = dict(opts.hv_state)
267 c4929a8b René Nussbaumer
268 0359e5d0 Spyros Trigazis
  default_ialloc_params = opts.default_iallocator_params
269 a0c9f010 Michael Hanselmann
  bootstrap.InitCluster(cluster_name=args[0],
270 a0c9f010 Michael Hanselmann
                        secondary_ip=opts.secondary_ip,
271 a0c9f010 Michael Hanselmann
                        vg_name=vg_name,
272 a0c9f010 Michael Hanselmann
                        mac_prefix=opts.mac_prefix,
273 5a8648eb Andrea Spadaccini
                        master_netmask=master_netmask,
274 25be0c75 Guido Trotter
                        master_netdev=master_netdev,
275 ea3a925f Alexander Schreiber
                        file_storage_dir=opts.file_storage_dir,
276 7925d409 Apollon Oikonomopoulos
                        shared_file_storage_dir=opts.shared_file_storage_dir,
277 d3e6fd0e Santi Raffa
                        gluster_storage_dir=opts.gluster_storage_dir,
278 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
279 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
280 ce735215 Guido Trotter
                        beparams=beparams,
281 b6a30b0d Guido Trotter
                        nicparams=nicparams,
282 6204ee71 René Nussbaumer
                        ndparams=ndparams,
283 bc5d0215 Andrea Spadaccini
                        diskparams=diskparams,
284 18bb6d28 Agata Murawska
                        ipolicy=ipolicy,
285 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
286 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
287 b989b9d9 Ken Wehr
                        modify_ssh_setup=opts.modify_ssh_setup,
288 3953242f Iustin Pop
                        maintain_node_health=opts.maintain_node_health,
289 ed14ed48 Luca Bigliardi
                        drbd_helper=drbd_helper,
290 39b0f0c2 Balazs Lecz
                        uid_pool=uid_pool,
291 bf4af505 Apollon Oikonomopoulos
                        default_iallocator=opts.default_iallocator,
292 0359e5d0 Spyros Trigazis
                        default_iallocator_params=default_ialloc_params,
293 e7323b5e Manuel Franceschini
                        primary_ip_version=primary_ip_version,
294 b18ecea2 René Nussbaumer
                        prealloc_wipe_disks=opts.prealloc_wipe_disks,
295 bf689b7a Andrea Spadaccini
                        use_external_mip_script=external_ip_setup_script,
296 c4929a8b René Nussbaumer
                        hv_state=hv_state,
297 c4929a8b René Nussbaumer
                        disk_state=disk_state,
298 3bde79ee Helga Velroyen
                        enabled_disk_templates=enabled_disk_templates,
299 ce735215 Guido Trotter
                        )
300 bc84ffa7 Iustin Pop
  op = opcodes.OpClusterPostInit()
301 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
302 a8083063 Iustin Pop
  return 0
303 a8083063 Iustin Pop
304 a8083063 Iustin Pop
305 4331f6cd Michael Hanselmann
@UsesRPC
306 a8083063 Iustin Pop
def DestroyCluster(opts, args):
307 a8083063 Iustin Pop
  """Destroy the cluster.
308 a8083063 Iustin Pop

309 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
310 469ee405 Iustin Pop
  @type args: list
311 469ee405 Iustin Pop
  @param args: should be an empty list
312 469ee405 Iustin Pop
  @rtype: int
313 469ee405 Iustin Pop
  @return: the desired exit code
314 098c0958 Michael Hanselmann

315 a8083063 Iustin Pop
  """
316 a8083063 Iustin Pop
  if not opts.yes_do_it:
317 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
318 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
319 a8083063 Iustin Pop
    return 1
320 a8083063 Iustin Pop
321 c6d43e9e Iustin Pop
  op = opcodes.OpClusterDestroy()
322 1c3231aa Thomas Thrainer
  master_uuid = SubmitOpCode(op, opts=opts)
323 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
324 140aa4a8 Iustin Pop
  # shutdown all the daemons
325 1c3231aa Thomas Thrainer
  bootstrap.FinalizeClusterDestroy(master_uuid)
326 a8083063 Iustin Pop
  return 0
327 a8083063 Iustin Pop
328 a8083063 Iustin Pop
329 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
330 07bd8a51 Iustin Pop
  """Rename the cluster.
331 07bd8a51 Iustin Pop

332 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
333 469ee405 Iustin Pop
  @type args: list
334 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
335 469ee405 Iustin Pop
  @rtype: int
336 469ee405 Iustin Pop
  @return: the desired exit code
337 07bd8a51 Iustin Pop

338 07bd8a51 Iustin Pop
  """
339 6a016df9 Michael Hanselmann
  cl = GetClient()
340 6a016df9 Michael Hanselmann
341 6a016df9 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
342 6a016df9 Michael Hanselmann
343 6a016df9 Michael Hanselmann
  new_name = args[0]
344 07bd8a51 Iustin Pop
  if not opts.force:
345 6a016df9 Michael Hanselmann
    usertext = ("This will rename the cluster from '%s' to '%s'. If you are"
346 6a016df9 Michael Hanselmann
                " connected over the network to the cluster name, the"
347 6a016df9 Michael Hanselmann
                " operation is very dangerous as the IP address will be"
348 6a016df9 Michael Hanselmann
                " removed from the node and the change may not go through."
349 6a016df9 Michael Hanselmann
                " Continue?") % (cluster_name, new_name)
350 47988778 Iustin Pop
    if not AskUser(usertext):
351 07bd8a51 Iustin Pop
      return 1
352 07bd8a51 Iustin Pop
353 e126df25 Iustin Pop
  op = opcodes.OpClusterRename(name=new_name)
354 6a016df9 Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
355 6a016df9 Michael Hanselmann
356 48418fea Iustin Pop
  if result:
357 48418fea Iustin Pop
    ToStdout("Cluster renamed from '%s' to '%s'", cluster_name, result)
358 6a016df9 Michael Hanselmann
359 07bd8a51 Iustin Pop
  return 0
360 07bd8a51 Iustin Pop
361 07bd8a51 Iustin Pop
362 fb926117 Andrea Spadaccini
def ActivateMasterIp(opts, args):
363 fb926117 Andrea Spadaccini
  """Activates the master IP.
364 fb926117 Andrea Spadaccini

365 fb926117 Andrea Spadaccini
  """
366 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
367 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
368 fb926117 Andrea Spadaccini
  return 0
369 fb926117 Andrea Spadaccini
370 fb926117 Andrea Spadaccini
371 fb926117 Andrea Spadaccini
def DeactivateMasterIp(opts, args):
372 fb926117 Andrea Spadaccini
  """Deactivates the master IP.
373 fb926117 Andrea Spadaccini

374 fb926117 Andrea Spadaccini
  """
375 fb926117 Andrea Spadaccini
  if not opts.confirm:
376 fb926117 Andrea Spadaccini
    usertext = ("This will disable the master IP. All the open connections to"
377 fb926117 Andrea Spadaccini
                " the master IP will be closed. To reach the master you will"
378 fb926117 Andrea Spadaccini
                " need to use its node IP."
379 fb926117 Andrea Spadaccini
                " Continue?")
380 fb926117 Andrea Spadaccini
    if not AskUser(usertext):
381 fb926117 Andrea Spadaccini
      return 1
382 fb926117 Andrea Spadaccini
383 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterDeactivateMasterIp()
384 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
385 fb926117 Andrea Spadaccini
  return 0
386 fb926117 Andrea Spadaccini
387 fb926117 Andrea Spadaccini
388 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
389 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
390 afee0879 Iustin Pop

391 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
392 afee0879 Iustin Pop
  @type args: list
393 afee0879 Iustin Pop
  @param args: empty list
394 afee0879 Iustin Pop
  @rtype: int
395 afee0879 Iustin Pop
  @return: the desired exit code
396 afee0879 Iustin Pop

397 afee0879 Iustin Pop
  """
398 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
399 0c455e40 Klaus Aehlig
  if opts.yes_do_it:
400 0c455e40 Klaus Aehlig
    SubmitOpCodeToDrainedQueue(op)
401 0c455e40 Klaus Aehlig
  else:
402 0c455e40 Klaus Aehlig
    SubmitOrSend(op, opts)
403 afee0879 Iustin Pop
  return 0
404 afee0879 Iustin Pop
405 afee0879 Iustin Pop
406 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
407 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
408 a8083063 Iustin Pop

409 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
410 469ee405 Iustin Pop
  @type args: list
411 469ee405 Iustin Pop
  @param args: should be an empty list
412 469ee405 Iustin Pop
  @rtype: int
413 469ee405 Iustin Pop
  @return: the desired exit code
414 a8083063 Iustin Pop

415 a8083063 Iustin Pop
  """
416 2af8b9c9 Klaus Aehlig
  cl = GetClient()
417 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
418 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
419 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
420 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
421 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
422 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
423 026f444f Thomas Thrainer
  ToStdout("VCS version: %s", result["vcs_version"])
424 a8083063 Iustin Pop
  return 0
425 a8083063 Iustin Pop
426 a8083063 Iustin Pop
427 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
428 a8083063 Iustin Pop
  """Write name of master node to the standard output.
429 a8083063 Iustin Pop

430 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
431 469ee405 Iustin Pop
  @type args: list
432 469ee405 Iustin Pop
  @param args: should be an empty list
433 469ee405 Iustin Pop
  @rtype: int
434 469ee405 Iustin Pop
  @return: the desired exit code
435 a8083063 Iustin Pop

436 a8083063 Iustin Pop
  """
437 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
438 8eb148ae Iustin Pop
  ToStdout(master)
439 a8083063 Iustin Pop
  return 0
440 a8083063 Iustin Pop
441 cac599f1 Michael Hanselmann
442 0e79564a Bernardo Dal Seno
def _FormatGroupedParams(paramsdict, roman=False):
443 0e79564a Bernardo Dal Seno
  """Format Grouped parameters (be, nic, disk) by group.
444 1094acda Guido Trotter

445 1094acda Guido Trotter
  @type paramsdict: dict of dicts
446 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
447 0e79564a Bernardo Dal Seno
  @rtype: dict of dicts
448 0e79564a Bernardo Dal Seno
  @return: copy of the input dictionaries with strings as values
449 1094acda Guido Trotter

450 1094acda Guido Trotter
  """
451 0e79564a Bernardo Dal Seno
  ret = {}
452 0e79564a Bernardo Dal Seno
  for (item, val) in paramsdict.items():
453 664a9d73 René Nussbaumer
    if isinstance(val, dict):
454 0e79564a Bernardo Dal Seno
      ret[item] = _FormatGroupedParams(val, roman=roman)
455 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
456 0e79564a Bernardo Dal Seno
      ret[item] = compat.TryToRoman(val)
457 664a9d73 René Nussbaumer
    else:
458 0e79564a Bernardo Dal Seno
      ret[item] = str(val)
459 0e79564a Bernardo Dal Seno
  return ret
460 a8083063 Iustin Pop
461 cac599f1 Michael Hanselmann
462 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
463 a8083063 Iustin Pop
  """Shows cluster information.
464 a8083063 Iustin Pop

465 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
466 469ee405 Iustin Pop
  @type args: list
467 469ee405 Iustin Pop
  @param args: should be an empty list
468 469ee405 Iustin Pop
  @rtype: int
469 469ee405 Iustin Pop
  @return: the desired exit code
470 469ee405 Iustin Pop

471 a8083063 Iustin Pop
  """
472 2af8b9c9 Klaus Aehlig
  cl = GetClient()
473 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
474 a8083063 Iustin Pop
475 c118d1f4 Michael Hanselmann
  if result["tags"]:
476 1f864b60 Iustin Pop
    tags = utils.CommaJoin(utils.NiceSort(result["tags"]))
477 c118d1f4 Michael Hanselmann
  else:
478 c118d1f4 Michael Hanselmann
    tags = "(none)"
479 5a3ab484 Iustin Pop
  if result["reserved_lvs"]:
480 5a3ab484 Iustin Pop
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
481 5a3ab484 Iustin Pop
  else:
482 5a3ab484 Iustin Pop
    reserved_lvs = "(none)"
483 be499e31 Agata Murawska
484 df5e2a28 Klaus Aehlig
  enabled_hv = result["enabled_hypervisors"]
485 df5e2a28 Klaus Aehlig
  hvparams = dict((k, v) for k, v in result["hvparams"].iteritems()
486 df5e2a28 Klaus Aehlig
                  if k in enabled_hv)
487 df5e2a28 Klaus Aehlig
488 0e79564a Bernardo Dal Seno
  info = [
489 0e79564a Bernardo Dal Seno
    ("Cluster name", result["name"]),
490 0e79564a Bernardo Dal Seno
    ("Cluster UUID", result["uuid"]),
491 0e79564a Bernardo Dal Seno
492 0e79564a Bernardo Dal Seno
    ("Creation time", utils.FormatTime(result["ctime"])),
493 0e79564a Bernardo Dal Seno
    ("Modification time", utils.FormatTime(result["mtime"])),
494 0e79564a Bernardo Dal Seno
495 0e79564a Bernardo Dal Seno
    ("Master node", result["master"]),
496 0e79564a Bernardo Dal Seno
497 0e79564a Bernardo Dal Seno
    ("Architecture (this node)",
498 0e79564a Bernardo Dal Seno
     "%s (%s)" % (result["architecture"][0], result["architecture"][1])),
499 0e79564a Bernardo Dal Seno
500 0e79564a Bernardo Dal Seno
    ("Tags", tags),
501 0e79564a Bernardo Dal Seno
502 0e79564a Bernardo Dal Seno
    ("Default hypervisor", result["default_hypervisor"]),
503 df5e2a28 Klaus Aehlig
    ("Enabled hypervisors", utils.CommaJoin(enabled_hv)),
504 0e79564a Bernardo Dal Seno
505 df5e2a28 Klaus Aehlig
    ("Hypervisor parameters", _FormatGroupedParams(hvparams)),
506 0e79564a Bernardo Dal Seno
507 0e79564a Bernardo Dal Seno
    ("OS-specific hypervisor parameters",
508 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["os_hvp"])),
509 0e79564a Bernardo Dal Seno
510 0e79564a Bernardo Dal Seno
    ("OS parameters", _FormatGroupedParams(result["osparams"])),
511 0e79564a Bernardo Dal Seno
512 0e79564a Bernardo Dal Seno
    ("Hidden OSes", utils.CommaJoin(result["hidden_os"])),
513 0e79564a Bernardo Dal Seno
    ("Blacklisted OSes", utils.CommaJoin(result["blacklisted_os"])),
514 0e79564a Bernardo Dal Seno
515 0e79564a Bernardo Dal Seno
    ("Cluster parameters", [
516 0e79564a Bernardo Dal Seno
      ("candidate pool size",
517 0e79564a Bernardo Dal Seno
       compat.TryToRoman(result["candidate_pool_size"],
518 0e79564a Bernardo Dal Seno
                         convert=opts.roman_integers)),
519 178ad717 Klaus Aehlig
      ("maximal number of jobs running simultaneously",
520 178ad717 Klaus Aehlig
       compat.TryToRoman(result["max_running_jobs"],
521 178ad717 Klaus Aehlig
                         convert=opts.roman_integers)),
522 353bd75b Dimitris Bliablias
      ("mac prefix", result["mac_prefix"]),
523 0e79564a Bernardo Dal Seno
      ("master netdev", result["master_netdev"]),
524 0e79564a Bernardo Dal Seno
      ("master netmask", result["master_netmask"]),
525 0e79564a Bernardo Dal Seno
      ("use external master IP address setup script",
526 0e79564a Bernardo Dal Seno
       result["use_external_mip_script"]),
527 0e79564a Bernardo Dal Seno
      ("lvm volume group", result["volume_group_name"]),
528 0e79564a Bernardo Dal Seno
      ("lvm reserved volumes", reserved_lvs),
529 0e79564a Bernardo Dal Seno
      ("drbd usermode helper", result["drbd_usermode_helper"]),
530 0e79564a Bernardo Dal Seno
      ("file storage path", result["file_storage_dir"]),
531 0e79564a Bernardo Dal Seno
      ("shared file storage path", result["shared_file_storage_dir"]),
532 d3e6fd0e Santi Raffa
      ("gluster storage path", result["gluster_storage_dir"]),
533 0e79564a Bernardo Dal Seno
      ("maintenance of node health", result["maintain_node_health"]),
534 0e79564a Bernardo Dal Seno
      ("uid pool", uidpool.FormatUidPool(result["uid_pool"])),
535 0e79564a Bernardo Dal Seno
      ("default instance allocator", result["default_iallocator"]),
536 0359e5d0 Spyros Trigazis
      ("default instance allocator parameters",
537 0359e5d0 Spyros Trigazis
       result["default_iallocator_params"]),
538 0e79564a Bernardo Dal Seno
      ("primary ip version", result["primary_ip_version"]),
539 0e79564a Bernardo Dal Seno
      ("preallocation wipe disks", result["prealloc_wipe_disks"]),
540 0e79564a Bernardo Dal Seno
      ("OS search path", utils.CommaJoin(pathutils.OS_SEARCH_PATH)),
541 0e79564a Bernardo Dal Seno
      ("ExtStorage Providers search path",
542 0e79564a Bernardo Dal Seno
       utils.CommaJoin(pathutils.ES_SEARCH_PATH)),
543 966e1580 Helga Velroyen
      ("enabled disk templates",
544 966e1580 Helga Velroyen
       utils.CommaJoin(result["enabled_disk_templates"])),
545 8a5d326f Jose A. Lopes
      ("instance communication network",
546 8a5d326f Jose A. Lopes
       result["instance_communication_network"]),
547 0e79564a Bernardo Dal Seno
      ]),
548 0e79564a Bernardo Dal Seno
549 0e79564a Bernardo Dal Seno
    ("Default node parameters",
550 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["ndparams"], roman=opts.roman_integers)),
551 0e79564a Bernardo Dal Seno
552 0e79564a Bernardo Dal Seno
    ("Default instance parameters",
553 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["beparams"], roman=opts.roman_integers)),
554 0e79564a Bernardo Dal Seno
555 0e79564a Bernardo Dal Seno
    ("Default nic parameters",
556 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["nicparams"], roman=opts.roman_integers)),
557 0e79564a Bernardo Dal Seno
558 0e79564a Bernardo Dal Seno
    ("Default disk parameters",
559 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["diskparams"], roman=opts.roman_integers)),
560 0e79564a Bernardo Dal Seno
561 0e79564a Bernardo Dal Seno
    ("Instance policy - limits for instances",
562 d00884a2 Bernardo Dal Seno
     FormatPolicyInfo(result["ipolicy"], None, True)),
563 0e79564a Bernardo Dal Seno
    ]
564 0e79564a Bernardo Dal Seno
565 0e79564a Bernardo Dal Seno
  PrintGenericInfo(info)
566 a8083063 Iustin Pop
  return 0
567 a8083063 Iustin Pop
568 a8083063 Iustin Pop
569 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
570 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
571 a8083063 Iustin Pop

572 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
573 469ee405 Iustin Pop
  @type args: list
574 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
575 469ee405 Iustin Pop
      the file to be copied
576 469ee405 Iustin Pop
  @rtype: int
577 469ee405 Iustin Pop
  @return: the desired exit code
578 a8083063 Iustin Pop

579 a8083063 Iustin Pop
  """
580 b3989551 Iustin Pop
  filename = args[0]
581 b3989551 Iustin Pop
  if not os.path.exists(filename):
582 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
583 debac808 Iustin Pop
                               errors.ECODE_INVAL)
584 b3989551 Iustin Pop
585 56bece1f Iustin Pop
  cl = GetClient()
586 2af8b9c9 Klaus Aehlig
  qcl = GetClient()
587 651ce6a3 Petr Pudlak
  try:
588 651ce6a3 Petr Pudlak
    cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
589 56bece1f Iustin Pop
590 bc57fa8d Helga Velroyen
    results = GetOnlineNodes(nodes=opts.nodes, cl=qcl, filter_master=True,
591 651ce6a3 Petr Pudlak
                             secondary_ips=opts.use_replication_network,
592 651ce6a3 Petr Pudlak
                             nodegroup=opts.nodegroup)
593 bc57fa8d Helga Velroyen
    ports = GetNodesSshPorts(opts.nodes, qcl)
594 651ce6a3 Petr Pudlak
  finally:
595 651ce6a3 Petr Pudlak
    cl.Close()
596 bc57fa8d Helga Velroyen
    qcl.Close()
597 e00ea635 Michael Hanselmann
598 224ff0f7 Michael Hanselmann
  srun = ssh.SshRunner(cluster_name)
599 651ce6a3 Petr Pudlak
  for (node, port) in zip(results, ports):
600 651ce6a3 Petr Pudlak
    if not srun.CopyFileToNode(node, port, filename):
601 651ce6a3 Petr Pudlak
      ToStderr("Copy of file %s to node %s:%d failed", filename, node, port)
602 b3989551 Iustin Pop
603 a8083063 Iustin Pop
  return 0
604 a8083063 Iustin Pop
605 a8083063 Iustin Pop
606 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
607 a8083063 Iustin Pop
  """Run a command on some nodes.
608 a8083063 Iustin Pop

609 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
610 469ee405 Iustin Pop
  @type args: list
611 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
612 469ee405 Iustin Pop
  @rtype: int
613 469ee405 Iustin Pop
  @return: the desired exit code
614 a8083063 Iustin Pop

615 a8083063 Iustin Pop
  """
616 56bece1f Iustin Pop
  cl = GetClient()
617 2af8b9c9 Klaus Aehlig
  qcl = GetClient()
618 7688d0d3 Michael Hanselmann
619 a8083063 Iustin Pop
  command = " ".join(args)
620 4040a784 Iustin Pop
621 bc57fa8d Helga Velroyen
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=qcl, nodegroup=opts.nodegroup)
622 bc57fa8d Helga Velroyen
  ports = GetNodesSshPorts(nodes, qcl)
623 56bece1f Iustin Pop
624 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
625 56bece1f Iustin Pop
                                                    "master_node"])
626 b3989551 Iustin Pop
627 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
628 b3989551 Iustin Pop
629 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
630 b3989551 Iustin Pop
  if master_node in nodes:
631 b3989551 Iustin Pop
    nodes.remove(master_node)
632 b3989551 Iustin Pop
    nodes.append(master_node)
633 b3989551 Iustin Pop
634 651ce6a3 Petr Pudlak
  for (name, port) in zip(nodes, ports):
635 651ce6a3 Petr Pudlak
    result = srun.Run(name, constants.SSH_LOGIN_USER, command, port=port)
636 d5b031dc Michael Hanselmann
637 d5b031dc Michael Hanselmann
    if opts.failure_only and result.exit_code == constants.EXIT_SUCCESS:
638 d5b031dc Michael Hanselmann
      # Do not output anything for successful commands
639 d5b031dc Michael Hanselmann
      continue
640 d5b031dc Michael Hanselmann
641 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
642 a24aed2a Michael Hanselmann
    if opts.show_machine_names:
643 a24aed2a Michael Hanselmann
      for line in result.output.splitlines():
644 a24aed2a Michael Hanselmann
        ToStdout("%s: %s", name, line)
645 a24aed2a Michael Hanselmann
    else:
646 a24aed2a Michael Hanselmann
      ToStdout("node: %s", name)
647 a24aed2a Michael Hanselmann
      ToStdout("%s", result.output)
648 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
649 b3989551 Iustin Pop
650 b3989551 Iustin Pop
  return 0
651 a8083063 Iustin Pop
652 a8083063 Iustin Pop
653 a8083063 Iustin Pop
def VerifyCluster(opts, args):
654 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
655 a8083063 Iustin Pop

656 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
657 469ee405 Iustin Pop
  @type args: list
658 469ee405 Iustin Pop
  @param args: should be an empty list
659 469ee405 Iustin Pop
  @rtype: int
660 469ee405 Iustin Pop
  @return: the desired exit code
661 a8083063 Iustin Pop

662 a8083063 Iustin Pop
  """
663 8d59409f Iustin Pop
  skip_checks = []
664 bf93ae69 Adeodato Simo
665 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
666 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
667 bf93ae69 Adeodato Simo
668 fcad7225 Michael Hanselmann
  cl = GetClient()
669 bf93ae69 Adeodato Simo
670 fcad7225 Michael Hanselmann
  op = opcodes.OpClusterVerify(verbose=opts.verbose,
671 fcad7225 Michael Hanselmann
                               error_codes=opts.error_codes,
672 fcad7225 Michael Hanselmann
                               debug_simulate_errors=opts.simulate_errors,
673 fcad7225 Michael Hanselmann
                               skip_checks=skip_checks,
674 93f2399e Andrea Spadaccini
                               ignore_errors=opts.ignore_errors,
675 fcad7225 Michael Hanselmann
                               group_name=opts.nodegroup)
676 fcad7225 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
677 bf93ae69 Adeodato Simo
678 fcad7225 Michael Hanselmann
  # Keep track of submitted jobs
679 fcad7225 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
680 fcad7225 Michael Hanselmann
681 fcad7225 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
682 fcad7225 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
683 bf93ae69 Adeodato Simo
684 fcad7225 Michael Hanselmann
  results = jex.GetResults()
685 ebe6cf38 Michael Hanselmann
686 ebe6cf38 Michael Hanselmann
  (bad_jobs, bad_results) = \
687 ebe6cf38 Michael Hanselmann
    map(len,
688 ebe6cf38 Michael Hanselmann
        # Convert iterators to lists
689 ebe6cf38 Michael Hanselmann
        map(list,
690 ebe6cf38 Michael Hanselmann
            # Count errors
691 ebe6cf38 Michael Hanselmann
            map(compat.partial(itertools.ifilterfalse, bool),
692 ebe6cf38 Michael Hanselmann
                # Convert result to booleans in a tuple
693 ebe6cf38 Michael Hanselmann
                zip(*((job_success, len(op_results) == 1 and op_results[0])
694 ebe6cf38 Michael Hanselmann
                      for (job_success, op_results) in results)))))
695 ebe6cf38 Michael Hanselmann
696 ebe6cf38 Michael Hanselmann
  if bad_jobs == 0 and bad_results == 0:
697 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
698 e0508c86 Guido Trotter
  else:
699 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
700 ebe6cf38 Michael Hanselmann
    if bad_jobs > 0:
701 ebe6cf38 Michael Hanselmann
      ToStdout("%s job(s) failed while verifying the cluster.", bad_jobs)
702 fcad7225 Michael Hanselmann
703 fcad7225 Michael Hanselmann
  return rcode
704 a8083063 Iustin Pop
705 a8083063 Iustin Pop
706 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
707 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
708 f4d4e184 Iustin Pop

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

715 f4d4e184 Iustin Pop
  """
716 f1b083ce Michael Hanselmann
  cl = GetClient()
717 f1b083ce Michael Hanselmann
718 bd8210a7 Iustin Pop
  op = opcodes.OpClusterVerifyDisks()
719 f4d4e184 Iustin Pop
720 ae1a845c Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
721 ae1a845c Michael Hanselmann
722 ae1a845c Michael Hanselmann
  # Keep track of submitted jobs
723 ae1a845c Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
724 ae1a845c Michael Hanselmann
725 ae1a845c Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
726 ae1a845c Michael Hanselmann
    jex.AddJobId(None, status, job_id)
727 b63ed789 Iustin Pop
728 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
729 b63ed789 Iustin Pop
730 ae1a845c Michael Hanselmann
  for (status, result) in jex.GetResults():
731 ae1a845c Michael Hanselmann
    if not status:
732 ae1a845c Michael Hanselmann
      ToStdout("Job failed: %s", result)
733 ae1a845c Michael Hanselmann
      continue
734 ae1a845c Michael Hanselmann
735 ae1a845c Michael Hanselmann
    ((bad_nodes, instances, missing), ) = result
736 ae1a845c Michael Hanselmann
737 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
738 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
739 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
740 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
741 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
742 b63ed789 Iustin Pop
743 f4d4e184 Iustin Pop
    for iname in instances:
744 b63ed789 Iustin Pop
      if iname in missing:
745 b63ed789 Iustin Pop
        continue
746 83f5d475 Iustin Pop
      op = opcodes.OpInstanceActivateDisks(instance_name=iname)
747 f4d4e184 Iustin Pop
      try:
748 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
749 f1b083ce Michael Hanselmann
        SubmitOpCode(op, opts=opts, cl=cl)
750 f4d4e184 Iustin Pop
      except errors.GenericError, err:
751 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
752 f4d4e184 Iustin Pop
        retcode |= nret
753 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
754 b63ed789 Iustin Pop
755 ae1a845c Michael Hanselmann
    if missing:
756 ae1a845c Michael Hanselmann
      for iname, ival in missing.iteritems():
757 ae1a845c Michael Hanselmann
        all_missing = compat.all(x[0] in bad_nodes for x in ival)
758 ae1a845c Michael Hanselmann
        if all_missing:
759 ae1a845c Michael Hanselmann
          ToStdout("Instance %s cannot be verified as it lives on"
760 ae1a845c Michael Hanselmann
                   " broken nodes", iname)
761 ae1a845c Michael Hanselmann
        else:
762 ae1a845c Michael Hanselmann
          ToStdout("Instance %s has missing logical volumes:", iname)
763 ae1a845c Michael Hanselmann
          ival.sort()
764 ae1a845c Michael Hanselmann
          for node, vol in ival:
765 ae1a845c Michael Hanselmann
            if node in bad_nodes:
766 ae1a845c Michael Hanselmann
              ToStdout("\tbroken node %s /dev/%s", node, vol)
767 ae1a845c Michael Hanselmann
            else:
768 ae1a845c Michael Hanselmann
              ToStdout("\t%s /dev/%s", node, vol)
769 ae1a845c Michael Hanselmann
770 ae1a845c Michael Hanselmann
      ToStdout("You need to replace or recreate disks for all the above"
771 ae1a845c Michael Hanselmann
               " instances if this message persists after fixing broken nodes.")
772 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
773 9b99be28 Michael Hanselmann
    elif not instances:
774 9b99be28 Michael Hanselmann
      ToStdout("No disks need to be activated.")
775 f4d4e184 Iustin Pop
776 f4d4e184 Iustin Pop
  return retcode
777 f4d4e184 Iustin Pop
778 f4d4e184 Iustin Pop
779 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
780 60975797 Iustin Pop
  """Verify sizes of cluster disks.
781 60975797 Iustin Pop

782 60975797 Iustin Pop
  @param opts: the command line options selected by the user
783 60975797 Iustin Pop
  @type args: list
784 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
785 60975797 Iustin Pop
  @rtype: int
786 60975797 Iustin Pop
  @return: the desired exit code
787 60975797 Iustin Pop

788 60975797 Iustin Pop
  """
789 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
790 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
791 60975797 Iustin Pop
792 60975797 Iustin Pop
793 4331f6cd Michael Hanselmann
@UsesRPC
794 a8083063 Iustin Pop
def MasterFailover(opts, args):
795 a8083063 Iustin Pop
  """Failover the master node.
796 a8083063 Iustin Pop

797 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
798 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
799 a8083063 Iustin Pop
  master.
800 a8083063 Iustin Pop

801 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
802 469ee405 Iustin Pop
  @type args: list
803 469ee405 Iustin Pop
  @param args: should be an empty list
804 469ee405 Iustin Pop
  @rtype: int
805 469ee405 Iustin Pop
  @return: the desired exit code
806 469ee405 Iustin Pop

807 a8083063 Iustin Pop
  """
808 6022a419 Iustin Pop
  if opts.no_voting and not opts.yes_do_it:
809 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
810 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
811 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
812 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
813 8e2524c3 Guido Trotter
    if not AskUser(usertext):
814 8e2524c3 Guido Trotter
      return 1
815 8e2524c3 Guido Trotter
816 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
817 a8083063 Iustin Pop
818 a8083063 Iustin Pop
819 4404ffad Iustin Pop
def MasterPing(opts, args):
820 4404ffad Iustin Pop
  """Checks if the master is alive.
821 4404ffad Iustin Pop

822 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
823 4404ffad Iustin Pop
  @type args: list
824 4404ffad Iustin Pop
  @param args: should be an empty list
825 4404ffad Iustin Pop
  @rtype: int
826 4404ffad Iustin Pop
  @return: the desired exit code
827 4404ffad Iustin Pop

828 4404ffad Iustin Pop
  """
829 4404ffad Iustin Pop
  try:
830 4404ffad Iustin Pop
    cl = GetClient()
831 4404ffad Iustin Pop
    cl.QueryClusterInfo()
832 4404ffad Iustin Pop
    return 0
833 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
834 4404ffad Iustin Pop
    return 1
835 4404ffad Iustin Pop
836 4404ffad Iustin Pop
837 73415719 Iustin Pop
def SearchTags(opts, args):
838 73415719 Iustin Pop
  """Searches the tags on all the cluster.
839 73415719 Iustin Pop

840 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
841 469ee405 Iustin Pop
  @type args: list
842 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
843 469ee405 Iustin Pop
  @rtype: int
844 469ee405 Iustin Pop
  @return: the desired exit code
845 469ee405 Iustin Pop

846 73415719 Iustin Pop
  """
847 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
848 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
849 73415719 Iustin Pop
  if not result:
850 73415719 Iustin Pop
    return 1
851 73415719 Iustin Pop
  result = list(result)
852 73415719 Iustin Pop
  result.sort()
853 73415719 Iustin Pop
  for path, tag in result:
854 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
855 73415719 Iustin Pop
856 73415719 Iustin Pop
857 b6267745 Andrea Spadaccini
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
858 b6267745 Andrea Spadaccini
  """Reads and verifies an X509 certificate.
859 b6267745 Andrea Spadaccini

860 b6267745 Andrea Spadaccini
  @type cert_filename: string
861 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
862 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
863 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
864 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
865 b6267745 Andrea Spadaccini
                             the public certificate
866 b6267745 Andrea Spadaccini
  @rtype: string
867 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
868 b6267745 Andrea Spadaccini

869 b6267745 Andrea Spadaccini
  """
870 b6267745 Andrea Spadaccini
  try:
871 b6267745 Andrea Spadaccini
    pem = utils.ReadFile(cert_filename)
872 b6267745 Andrea Spadaccini
  except IOError, err:
873 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
874 b6267745 Andrea Spadaccini
                               "Unable to read certificate: %s" % str(err))
875 b6267745 Andrea Spadaccini
876 b6267745 Andrea Spadaccini
  try:
877 b6267745 Andrea Spadaccini
    OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
878 b6267745 Andrea Spadaccini
  except Exception, err:
879 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
880 b6267745 Andrea Spadaccini
                               "Unable to load certificate: %s" % str(err))
881 b6267745 Andrea Spadaccini
882 b6267745 Andrea Spadaccini
  if verify_private_key:
883 b6267745 Andrea Spadaccini
    try:
884 b6267745 Andrea Spadaccini
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, pem)
885 b6267745 Andrea Spadaccini
    except Exception, err:
886 b6267745 Andrea Spadaccini
      raise errors.X509CertError(cert_filename,
887 b6267745 Andrea Spadaccini
                                 "Unable to load private key: %s" % str(err))
888 b6267745 Andrea Spadaccini
889 b6267745 Andrea Spadaccini
  return pem
890 b6267745 Andrea Spadaccini
891 b6267745 Andrea Spadaccini
892 5ae4945a Iustin Pop
def _RenewCrypto(new_cluster_cert, new_rapi_cert, # pylint: disable=R0911
893 b6267745 Andrea Spadaccini
                 rapi_cert_filename, new_spice_cert, spice_cert_filename,
894 b6267745 Andrea Spadaccini
                 spice_cacert_filename, new_confd_hmac_key, new_cds,
895 b3cc1646 Helga Velroyen
                 cds_filename, force, new_node_cert):
896 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
897 6d4a1656 Michael Hanselmann

898 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
899 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
900 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
901 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
902 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
903 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
904 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
905 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
906 b6267745 Andrea Spadaccini
  @type spice_cert_filename: string
907 b6267745 Andrea Spadaccini
  @param spice_cert_filename: Path to file containing new SPICE certificate
908 b6267745 Andrea Spadaccini
  @type spice_cacert_filename: string
909 b6267745 Andrea Spadaccini
  @param spice_cacert_filename: Path to file containing the certificate of the
910 b6267745 Andrea Spadaccini
                                CA that signed the SPICE certificate
911 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
912 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
913 3db3eb2a Michael Hanselmann
  @type new_cds: bool
914 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
915 3db3eb2a Michael Hanselmann
  @type cds_filename: string
916 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
917 6d4a1656 Michael Hanselmann
  @type force: bool
918 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
919 b3cc1646 Helga Velroyen
  @type new_node_cert: string
920 b3cc1646 Helga Velroyen
  @param new_node_cert: Whether to generate new node certificates
921 6d4a1656 Michael Hanselmann

922 6d4a1656 Michael Hanselmann
  """
923 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
924 6e060e15 Andrea Spadaccini
    ToStderr("Only one of the --new-rapi-certificate and --rapi-certificate"
925 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
926 6d4a1656 Michael Hanselmann
    return 1
927 6d4a1656 Michael Hanselmann
928 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
929 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
930 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
931 3db3eb2a Michael Hanselmann
             " the same time.")
932 3db3eb2a Michael Hanselmann
    return 1
933 3db3eb2a Michael Hanselmann
934 b6267745 Andrea Spadaccini
  if new_spice_cert and (spice_cert_filename or spice_cacert_filename):
935 b6267745 Andrea Spadaccini
    ToStderr("When using --new-spice-certificate, the --spice-certificate"
936 b6267745 Andrea Spadaccini
             " and --spice-ca-certificate must not be used.")
937 b6267745 Andrea Spadaccini
    return 1
938 6d4a1656 Michael Hanselmann
939 b6267745 Andrea Spadaccini
  if bool(spice_cacert_filename) ^ bool(spice_cert_filename):
940 b6267745 Andrea Spadaccini
    ToStderr("Both --spice-certificate and --spice-ca-certificate must be"
941 b6267745 Andrea Spadaccini
             " specified.")
942 b6267745 Andrea Spadaccini
    return 1
943 6d4a1656 Michael Hanselmann
944 b6267745 Andrea Spadaccini
  rapi_cert_pem, spice_cert_pem, spice_cacert_pem = (None, None, None)
945 b6267745 Andrea Spadaccini
  try:
946 b6267745 Andrea Spadaccini
    if rapi_cert_filename:
947 b6267745 Andrea Spadaccini
      rapi_cert_pem = _ReadAndVerifyCert(rapi_cert_filename, True)
948 b6267745 Andrea Spadaccini
    if spice_cert_filename:
949 b6267745 Andrea Spadaccini
      spice_cert_pem = _ReadAndVerifyCert(spice_cert_filename, True)
950 b6267745 Andrea Spadaccini
      spice_cacert_pem = _ReadAndVerifyCert(spice_cacert_filename)
951 b6267745 Andrea Spadaccini
  except errors.X509CertError, err:
952 b6267745 Andrea Spadaccini
    ToStderr("Unable to load X509 certificate from %s: %s", err[0], err[1])
953 b6267745 Andrea Spadaccini
    return 1
954 6d4a1656 Michael Hanselmann
955 3db3eb2a Michael Hanselmann
  if cds_filename:
956 3db3eb2a Michael Hanselmann
    try:
957 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
958 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
959 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
960 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
961 3db3eb2a Michael Hanselmann
      return 1
962 3db3eb2a Michael Hanselmann
  else:
963 3db3eb2a Michael Hanselmann
    cds = None
964 3db3eb2a Michael Hanselmann
965 6d4a1656 Michael Hanselmann
  if not force:
966 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
967 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
968 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
969 6d4a1656 Michael Hanselmann
      return 1
970 6d4a1656 Michael Hanselmann
971 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
972 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
973 b3cc1646 Helga Velroyen
    # Note: the node certificate will be generated in the LU
974 b6267745 Andrea Spadaccini
    bootstrap.GenerateClusterCrypto(new_cluster_cert,
975 b6267745 Andrea Spadaccini
                                    new_rapi_cert,
976 b6267745 Andrea Spadaccini
                                    new_spice_cert,
977 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
978 3db3eb2a Michael Hanselmann
                                    new_cds,
979 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
980 b6267745 Andrea Spadaccini
                                    spice_cert_pem=spice_cert_pem,
981 b6267745 Andrea Spadaccini
                                    spice_cacert_pem=spice_cacert_pem,
982 3db3eb2a Michael Hanselmann
                                    cds=cds)
983 6d4a1656 Michael Hanselmann
984 6d4a1656 Michael Hanselmann
    files_to_copy = []
985 6d4a1656 Michael Hanselmann
986 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
987 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.NODED_CERT_FILE)
988 6d4a1656 Michael Hanselmann
989 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
990 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.RAPI_CERT_FILE)
991 6d4a1656 Michael Hanselmann
992 b6267745 Andrea Spadaccini
    if new_spice_cert or spice_cert_pem:
993 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.SPICE_CERT_FILE)
994 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.SPICE_CACERT_FILE)
995 b6267745 Andrea Spadaccini
996 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
997 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.CONFD_HMAC_KEY)
998 6d4a1656 Michael Hanselmann
999 3db3eb2a Michael Hanselmann
    if new_cds or cds:
1000 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.CLUSTER_DOMAIN_SECRET_FILE)
1001 3db3eb2a Michael Hanselmann
1002 6d4a1656 Michael Hanselmann
    if files_to_copy:
1003 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
1004 651ce6a3 Petr Pudlak
        port = ctx.ssh_ports[node_name]
1005 651ce6a3 Petr Pudlak
        ctx.feedback_fn("Copying %s to %s:%d" %
1006 651ce6a3 Petr Pudlak
                        (", ".join(files_to_copy), node_name, port))
1007 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
1008 651ce6a3 Petr Pudlak
          ctx.ssh.CopyFileToNode(node_name, port, file_name)
1009 6d4a1656 Michael Hanselmann
1010 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
1011 6d4a1656 Michael Hanselmann
1012 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
1013 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
1014 6d4a1656 Michael Hanselmann
1015 b3cc1646 Helga Velroyen
  if new_node_cert:
1016 b3cc1646 Helga Velroyen
    cl = GetClient()
1017 b3cc1646 Helga Velroyen
    renew_op = opcodes.OpClusterRenewCrypto()
1018 b3cc1646 Helga Velroyen
    SubmitOpCode(renew_op, cl=cl)
1019 b3cc1646 Helga Velroyen
1020 6d4a1656 Michael Hanselmann
  return 0
1021 6d4a1656 Michael Hanselmann
1022 6d4a1656 Michael Hanselmann
1023 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
1024 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
1025 6d4a1656 Michael Hanselmann

1026 6d4a1656 Michael Hanselmann
  """
1027 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
1028 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
1029 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
1030 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
1031 b6267745 Andrea Spadaccini
                      opts.spice_cert,
1032 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
1033 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
1034 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
1035 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
1036 b3cc1646 Helga Velroyen
                      opts.force,
1037 b3cc1646 Helga Velroyen
                      opts.new_node_cert)
1038 6d4a1656 Michael Hanselmann
1039 6d4a1656 Michael Hanselmann
1040 c121d42f Helga Velroyen
def _GetEnabledDiskTemplates(opts):
1041 c121d42f Helga Velroyen
  """Determine the list of enabled disk templates.
1042 c121d42f Helga Velroyen

1043 c121d42f Helga Velroyen
  """
1044 c121d42f Helga Velroyen
  if opts.enabled_disk_templates:
1045 c121d42f Helga Velroyen
    return opts.enabled_disk_templates.split(",")
1046 c121d42f Helga Velroyen
  else:
1047 c121d42f Helga Velroyen
    return None
1048 c121d42f Helga Velroyen
1049 c121d42f Helga Velroyen
1050 c121d42f Helga Velroyen
def _GetVgName(opts, enabled_disk_templates):
1051 c121d42f Helga Velroyen
  """Determine the volume group name.
1052 c121d42f Helga Velroyen

1053 c121d42f Helga Velroyen
  @type enabled_disk_templates: list of strings
1054 c121d42f Helga Velroyen
  @param enabled_disk_templates: cluster-wide enabled disk-templates
1055 c121d42f Helga Velroyen

1056 c121d42f Helga Velroyen
  """
1057 c121d42f Helga Velroyen
  # consistency between vg name and enabled disk templates
1058 c121d42f Helga Velroyen
  vg_name = None
1059 c121d42f Helga Velroyen
  if opts.vg_name is not None:
1060 c121d42f Helga Velroyen
    vg_name = opts.vg_name
1061 c121d42f Helga Velroyen
  if enabled_disk_templates:
1062 c121d42f Helga Velroyen
    if vg_name and not utils.IsLvmEnabled(enabled_disk_templates):
1063 c121d42f Helga Velroyen
      ToStdout("You specified a volume group with --vg-name, but you did not"
1064 c121d42f Helga Velroyen
               " enable any of the following lvm-based disk templates: %s" %
1065 d48c944b Helga Velroyen
               utils.CommaJoin(constants.DTS_LVM))
1066 c121d42f Helga Velroyen
  return vg_name
1067 c121d42f Helga Velroyen
1068 c121d42f Helga Velroyen
1069 31ccfc0e Helga Velroyen
def _GetDrbdHelper(opts, enabled_disk_templates):
1070 c121d42f Helga Velroyen
  """Determine the DRBD usermode helper.
1071 c121d42f Helga Velroyen

1072 c121d42f Helga Velroyen
  """
1073 c121d42f Helga Velroyen
  drbd_helper = opts.drbd_helper
1074 31ccfc0e Helga Velroyen
  if enabled_disk_templates:
1075 31ccfc0e Helga Velroyen
    drbd_enabled = constants.DT_DRBD8 in enabled_disk_templates
1076 31ccfc0e Helga Velroyen
    if not drbd_enabled and opts.drbd_helper:
1077 38969795 Helga Velroyen
      ToStdout("You specified a DRBD usermode helper with "
1078 38969795 Helga Velroyen
               " --drbd-usermode-helper while DRBD is not enabled.")
1079 c121d42f Helga Velroyen
  return drbd_helper
1080 c121d42f Helga Velroyen
1081 c121d42f Helga Velroyen
1082 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
1083 90b6aa3a Manuel Franceschini
  """Modify the cluster.
1084 90b6aa3a Manuel Franceschini

1085 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1086 469ee405 Iustin Pop
  @type args: list
1087 469ee405 Iustin Pop
  @param args: should be an empty list
1088 469ee405 Iustin Pop
  @rtype: int
1089 469ee405 Iustin Pop
  @return: the desired exit code
1090 90b6aa3a Manuel Franceschini

1091 90b6aa3a Manuel Franceschini
  """
1092 31ccfc0e Helga Velroyen
  if not (opts.vg_name is not None or
1093 31ccfc0e Helga Velroyen
          opts.drbd_helper is not None or
1094 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
1095 bc5d0215 Andrea Spadaccini
          opts.beparams or opts.nicparams or
1096 bc5d0215 Andrea Spadaccini
          opts.ndparams or opts.diskparams or
1097 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
1098 ea22736b Klaus Aehlig
          opts.max_running_jobs is not None or
1099 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
1100 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
1101 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
1102 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
1103 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
1104 0359e5d0 Spyros Trigazis
          opts.default_iallocator_params or
1105 b883637f René Nussbaumer
          opts.reserved_lvs is not None or
1106 0cffcdb1 Dimitris Bliablias
          opts.mac_prefix is not None or
1107 38f9d2cf Guido Trotter
          opts.master_netdev is not None or
1108 5a8648eb Andrea Spadaccini
          opts.master_netmask is not None or
1109 bf689b7a Andrea Spadaccini
          opts.use_external_mip_script is not None or
1110 2da9f556 René Nussbaumer
          opts.prealloc_wipe_disks is not None or
1111 2da9f556 René Nussbaumer
          opts.hv_state or
1112 66af5ec5 Helga Velroyen
          opts.enabled_disk_templates or
1113 e1a6850f Agata Murawska
          opts.disk_state or
1114 d2d3935a Bernardo Dal Seno
          opts.ipolicy_bounds_specs is not None or
1115 d2d3935a Bernardo Dal Seno
          opts.ipolicy_std_specs is not None or
1116 1e7acc3b Iustin Pop
          opts.ipolicy_disk_templates is not None or
1117 31d827d1 René Nussbaumer
          opts.ipolicy_vcpu_ratio is not None or
1118 75f2ff7d Michele Tartara
          opts.ipolicy_spindle_ratio is not None or
1119 3039e2dc Helga Velroyen
          opts.modify_etc_hosts is not None or
1120 0fcb3314 Jose A. Lopes
          opts.file_storage_dir is not None or
1121 0fcb3314 Jose A. Lopes
          opts.instance_communication_network is not None):
1122 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
1123 90b6aa3a Manuel Franceschini
    return 1
1124 90b6aa3a Manuel Franceschini
1125 c121d42f Helga Velroyen
  enabled_disk_templates = _GetEnabledDiskTemplates(opts)
1126 c121d42f Helga Velroyen
  vg_name = _GetVgName(opts, enabled_disk_templates)
1127 90b6aa3a Manuel Franceschini
1128 c121d42f Helga Velroyen
  try:
1129 31ccfc0e Helga Velroyen
    drbd_helper = _GetDrbdHelper(opts, enabled_disk_templates)
1130 c121d42f Helga Velroyen
  except errors.OpPrereqError, e:
1131 c121d42f Helga Velroyen
    ToStderr(str(e))
1132 ed14ed48 Luca Bigliardi
    return 1
1133 ed14ed48 Luca Bigliardi
1134 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
1135 779c15bb Iustin Pop
  if hvlist is not None:
1136 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
1137 779c15bb Iustin Pop
1138 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
1139 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
1140 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
1141 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
1142 779c15bb Iustin Pop
1143 bc5d0215 Andrea Spadaccini
  diskparams = dict(opts.diskparams)
1144 bc5d0215 Andrea Spadaccini
1145 c20a19ed Iustin Pop
  for dt_params in diskparams.values():
1146 bc5d0215 Andrea Spadaccini
    utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
1147 bc5d0215 Andrea Spadaccini
1148 779c15bb Iustin Pop
  beparams = opts.beparams
1149 b2e233a5 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT)
1150 779c15bb Iustin Pop
1151 5af3da74 Guido Trotter
  nicparams = opts.nicparams
1152 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
1153 5af3da74 Guido Trotter
1154 6204ee71 René Nussbaumer
  ndparams = opts.ndparams
1155 6204ee71 René Nussbaumer
  if ndparams is not None:
1156 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
1157 1338f2b4 Balazs Lecz
1158 703fa9ab Iustin Pop
  ipolicy = CreateIPolicyFromOpts(
1159 d2d3935a Bernardo Dal Seno
    minmax_ispecs=opts.ipolicy_bounds_specs,
1160 d2d3935a Bernardo Dal Seno
    std_ispecs=opts.ipolicy_std_specs,
1161 976b78ba Iustin Pop
    ipolicy_disk_templates=opts.ipolicy_disk_templates,
1162 976b78ba Iustin Pop
    ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio,
1163 31d827d1 René Nussbaumer
    ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio,
1164 976b78ba Iustin Pop
    )
1165 e1a6850f Agata Murawska
1166 3953242f Iustin Pop
  mnh = opts.maintain_node_health
1167 3953242f Iustin Pop
1168 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
1169 1338f2b4 Balazs Lecz
  if uid_pool is not None:
1170 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
1171 1338f2b4 Balazs Lecz
1172 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
1173 fdad8c4d Balazs Lecz
  if add_uids is not None:
1174 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
1175 fdad8c4d Balazs Lecz
1176 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
1177 fdad8c4d Balazs Lecz
  if remove_uids is not None:
1178 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
1179 fdad8c4d Balazs Lecz
1180 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
1181 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
1182 f38ea602 Iustin Pop
      opts.reserved_lvs = []
1183 f38ea602 Iustin Pop
    else:
1184 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
1185 f38ea602 Iustin Pop
1186 5a8648eb Andrea Spadaccini
  if opts.master_netmask is not None:
1187 5a8648eb Andrea Spadaccini
    try:
1188 5a8648eb Andrea Spadaccini
      opts.master_netmask = int(opts.master_netmask)
1189 5a8648eb Andrea Spadaccini
    except ValueError:
1190 5a8648eb Andrea Spadaccini
      ToStderr("The --master-netmask option expects an int parameter.")
1191 5a8648eb Andrea Spadaccini
      return 1
1192 5a8648eb Andrea Spadaccini
1193 bf689b7a Andrea Spadaccini
  ext_ip_script = opts.use_external_mip_script
1194 bf689b7a Andrea Spadaccini
1195 2da9f556 René Nussbaumer
  if opts.disk_state:
1196 2da9f556 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
1197 2da9f556 René Nussbaumer
  else:
1198 2da9f556 René Nussbaumer
    disk_state = {}
1199 2da9f556 René Nussbaumer
1200 2da9f556 René Nussbaumer
  hv_state = dict(opts.hv_state)
1201 2da9f556 René Nussbaumer
1202 c270ee07 Helga Velroyen
  op = opcodes.OpClusterSetParams(
1203 c270ee07 Helga Velroyen
    vg_name=vg_name,
1204 c270ee07 Helga Velroyen
    drbd_helper=drbd_helper,
1205 c270ee07 Helga Velroyen
    enabled_hypervisors=hvlist,
1206 c270ee07 Helga Velroyen
    hvparams=hvparams,
1207 c270ee07 Helga Velroyen
    os_hvp=None,
1208 c270ee07 Helga Velroyen
    beparams=beparams,
1209 c270ee07 Helga Velroyen
    nicparams=nicparams,
1210 c270ee07 Helga Velroyen
    ndparams=ndparams,
1211 c270ee07 Helga Velroyen
    diskparams=diskparams,
1212 c270ee07 Helga Velroyen
    ipolicy=ipolicy,
1213 c270ee07 Helga Velroyen
    candidate_pool_size=opts.candidate_pool_size,
1214 ea22736b Klaus Aehlig
    max_running_jobs=opts.max_running_jobs,
1215 c270ee07 Helga Velroyen
    maintain_node_health=mnh,
1216 75f2ff7d Michele Tartara
    modify_etc_hosts=opts.modify_etc_hosts,
1217 c270ee07 Helga Velroyen
    uid_pool=uid_pool,
1218 c270ee07 Helga Velroyen
    add_uids=add_uids,
1219 c270ee07 Helga Velroyen
    remove_uids=remove_uids,
1220 c270ee07 Helga Velroyen
    default_iallocator=opts.default_iallocator,
1221 0359e5d0 Spyros Trigazis
    default_iallocator_params=opts.default_iallocator_params,
1222 c270ee07 Helga Velroyen
    prealloc_wipe_disks=opts.prealloc_wipe_disks,
1223 0cffcdb1 Dimitris Bliablias
    mac_prefix=opts.mac_prefix,
1224 c270ee07 Helga Velroyen
    master_netdev=opts.master_netdev,
1225 c270ee07 Helga Velroyen
    master_netmask=opts.master_netmask,
1226 c270ee07 Helga Velroyen
    reserved_lvs=opts.reserved_lvs,
1227 c270ee07 Helga Velroyen
    use_external_mip_script=ext_ip_script,
1228 c270ee07 Helga Velroyen
    hv_state=hv_state,
1229 c270ee07 Helga Velroyen
    disk_state=disk_state,
1230 66af5ec5 Helga Velroyen
    enabled_disk_templates=enabled_disk_templates,
1231 2f836021 Klaus Aehlig
    force=opts.force,
1232 3039e2dc Helga Velroyen
    file_storage_dir=opts.file_storage_dir,
1233 0fcb3314 Jose A. Lopes
    instance_communication_network=opts.instance_communication_network
1234 c270ee07 Helga Velroyen
    )
1235 0fcb3314 Jose A. Lopes
  return base.GetResult(None, opts, SubmitOrSend(op, opts))
1236 90b6aa3a Manuel Franceschini
1237 90b6aa3a Manuel Franceschini
1238 3ccafd0e Iustin Pop
def QueueOps(opts, args):
1239 3ccafd0e Iustin Pop
  """Queue operations.
1240 3ccafd0e Iustin Pop

1241 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1242 469ee405 Iustin Pop
  @type args: list
1243 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1244 469ee405 Iustin Pop
  @rtype: int
1245 469ee405 Iustin Pop
  @return: the desired exit code
1246 469ee405 Iustin Pop

1247 3ccafd0e Iustin Pop
  """
1248 3ccafd0e Iustin Pop
  command = args[0]
1249 3ccafd0e Iustin Pop
  client = GetClient()
1250 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
1251 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
1252 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
1253 3ccafd0e Iustin Pop
  elif command == "info":
1254 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
1255 3ccafd0e Iustin Pop
    if result[0]:
1256 3a24c527 Iustin Pop
      val = "set"
1257 3ccafd0e Iustin Pop
    else:
1258 3a24c527 Iustin Pop
      val = "unset"
1259 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
1260 2e668b38 Guido Trotter
  else:
1261 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1262 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1263 2e668b38 Guido Trotter
1264 3ccafd0e Iustin Pop
  return 0
1265 3ccafd0e Iustin Pop
1266 95b2e626 Michael Hanselmann
1267 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
1268 28b498cd Michael Hanselmann
  if until is None or until < time.time():
1269 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
1270 28b498cd Michael Hanselmann
  else:
1271 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
1272 28b498cd Michael Hanselmann
1273 28b498cd Michael Hanselmann
1274 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
1275 95b2e626 Michael Hanselmann
  """Watcher operations.
1276 95b2e626 Michael Hanselmann

1277 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1278 95b2e626 Michael Hanselmann
  @type args: list
1279 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1280 95b2e626 Michael Hanselmann
  @rtype: int
1281 95b2e626 Michael Hanselmann
  @return: the desired exit code
1282 95b2e626 Michael Hanselmann

1283 95b2e626 Michael Hanselmann
  """
1284 95b2e626 Michael Hanselmann
  command = args[0]
1285 95b2e626 Michael Hanselmann
  client = GetClient()
1286 95b2e626 Michael Hanselmann
1287 95b2e626 Michael Hanselmann
  if command == "continue":
1288 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
1289 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
1290 95b2e626 Michael Hanselmann
1291 95b2e626 Michael Hanselmann
  elif command == "pause":
1292 95b2e626 Michael Hanselmann
    if len(args) < 2:
1293 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
1294 95b2e626 Michael Hanselmann
1295 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
1296 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
1297 95b2e626 Michael Hanselmann
1298 95b2e626 Michael Hanselmann
  elif command == "info":
1299 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
1300 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
1301 95b2e626 Michael Hanselmann
1302 95b2e626 Michael Hanselmann
  else:
1303 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1304 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1305 95b2e626 Michael Hanselmann
1306 95b2e626 Michael Hanselmann
  return 0
1307 95b2e626 Michael Hanselmann
1308 95b2e626 Michael Hanselmann
1309 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
1310 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
1311 66d1f035 René Nussbaumer

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

1317 66d1f035 René Nussbaumer
  """
1318 66d1f035 René Nussbaumer
  if power:
1319 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
1320 66d1f035 René Nussbaumer
  else:
1321 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
1322 66d1f035 René Nussbaumer
1323 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
1324 66d1f035 René Nussbaumer
                            command=command,
1325 66d1f035 René Nussbaumer
                            ignore_status=True,
1326 cfed3b9f René Nussbaumer
                            timeout=opts.oob_timeout,
1327 cfed3b9f René Nussbaumer
                            power_delay=opts.power_delay)
1328 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
1329 66d1f035 René Nussbaumer
  errs = 0
1330 66d1f035 René Nussbaumer
  for node_result in result:
1331 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
1332 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
1333 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
1334 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
1335 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
1336 66d1f035 René Nussbaumer
      errs += 1
1337 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
1338 66d1f035 René Nussbaumer
               node_name)
1339 66d1f035 René Nussbaumer
1340 66d1f035 René Nussbaumer
  if errs > 0:
1341 66d1f035 René Nussbaumer
    return False
1342 66d1f035 René Nussbaumer
1343 66d1f035 René Nussbaumer
  return True
1344 66d1f035 René Nussbaumer
1345 66d1f035 René Nussbaumer
1346 3e0ed18c René Nussbaumer
def _InstanceStart(opts, inst_list, start, no_remember=False):
1347 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
1348 66d1f035 René Nussbaumer

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

1355 66d1f035 René Nussbaumer
  """
1356 66d1f035 René Nussbaumer
  if start:
1357 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
1358 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
1359 66d1f035 René Nussbaumer
  else:
1360 fcecea0b René Nussbaumer
    opcls = compat.partial(opcodes.OpInstanceShutdown,
1361 3e0ed18c René Nussbaumer
                           timeout=opts.shutdown_timeout,
1362 3e0ed18c René Nussbaumer
                           no_remember=no_remember)
1363 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
1364 66d1f035 René Nussbaumer
1365 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
1366 66d1f035 René Nussbaumer
1367 66d1f035 René Nussbaumer
  for inst in inst_list:
1368 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
1369 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
1370 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
1371 66d1f035 René Nussbaumer
1372 66d1f035 René Nussbaumer
  results = jex.GetResults()
1373 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
1374 66d1f035 René Nussbaumer
1375 66d1f035 René Nussbaumer
  if bad_cnt == 0:
1376 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
1377 66d1f035 René Nussbaumer
  else:
1378 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
1379 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
1380 66d1f035 René Nussbaumer
             len(results))
1381 66d1f035 René Nussbaumer
    return False
1382 66d1f035 René Nussbaumer
1383 66d1f035 René Nussbaumer
  return True
1384 66d1f035 René Nussbaumer
1385 66d1f035 René Nussbaumer
1386 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
1387 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
1388 66d1f035 René Nussbaumer

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

1391 66d1f035 René Nussbaumer
  """
1392 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1393 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1394 66d1f035 René Nussbaumer
    """Init the object.
1395 66d1f035 René Nussbaumer

1396 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1397 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1398 66d1f035 René Nussbaumer
    @type node2ip: dict
1399 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1400 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1401 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1402 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1403 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1404 66d1f035 René Nussbaumer

1405 66d1f035 René Nussbaumer
    """
1406 66d1f035 René Nussbaumer
    self.down = set(node_list)
1407 66d1f035 René Nussbaumer
    self.up = set()
1408 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1409 66d1f035 René Nussbaumer
    self.success = True
1410 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1411 66d1f035 René Nussbaumer
    self.port = port
1412 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1413 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1414 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1415 66d1f035 René Nussbaumer
1416 66d1f035 René Nussbaumer
  def __call__(self):
1417 66d1f035 René Nussbaumer
    """When called we run action_cb.
1418 66d1f035 René Nussbaumer

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

1421 66d1f035 René Nussbaumer
    """
1422 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1423 66d1f035 René Nussbaumer
      self.success = False
1424 66d1f035 René Nussbaumer
1425 66d1f035 René Nussbaumer
    if self.down:
1426 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1427 66d1f035 René Nussbaumer
    else:
1428 66d1f035 René Nussbaumer
      return self.success
1429 66d1f035 René Nussbaumer
1430 66d1f035 René Nussbaumer
  def Wait(self, secs):
1431 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1432 66d1f035 René Nussbaumer

1433 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1434 66d1f035 René Nussbaumer

1435 66d1f035 René Nussbaumer
    """
1436 66d1f035 René Nussbaumer
    start = time.time()
1437 66d1f035 René Nussbaumer
    for node in self.down:
1438 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1439 66d1f035 René Nussbaumer
                       live_port_needed=True):
1440 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1441 66d1f035 René Nussbaumer
        self.up.add(node)
1442 66d1f035 René Nussbaumer
        self.down -= self.up
1443 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1444 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1445 66d1f035 René Nussbaumer
        return
1446 66d1f035 René Nussbaumer
1447 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1448 66d1f035 René Nussbaumer
1449 66d1f035 René Nussbaumer
1450 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1451 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1452 66d1f035 René Nussbaumer

1453 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1454 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1455 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1456 66d1f035 René Nussbaumer

1457 66d1f035 René Nussbaumer
  """
1458 66d1f035 René Nussbaumer
  client = GetClient()
1459 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1460 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1461 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1462 66d1f035 René Nussbaumer
  else:
1463 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1464 66d1f035 René Nussbaumer
1465 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1466 66d1f035 René Nussbaumer
                 for node in node_list)
1467 66d1f035 René Nussbaumer
1468 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1469 8e74adce René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port,
1470 8e74adce René Nussbaumer
                                        ToStdout)
1471 66d1f035 René Nussbaumer
1472 66d1f035 René Nussbaumer
  try:
1473 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1474 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1475 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1476 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1477 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1478 66d1f035 René Nussbaumer
    return False
1479 66d1f035 René Nussbaumer
1480 66d1f035 René Nussbaumer
1481 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1482 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1483 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1484 66d1f035 René Nussbaumer

1485 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1486 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1487 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1488 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1489 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1490 66d1f035 René Nussbaumer

1491 66d1f035 René Nussbaumer
  """
1492 66d1f035 René Nussbaumer
  start_inst_list = []
1493 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1494 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1495 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1496 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1497 66d1f035 René Nussbaumer
1498 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1499 66d1f035 René Nussbaumer
    del inst_map[inst]
1500 66d1f035 René Nussbaumer
1501 66d1f035 René Nussbaumer
  if start_inst_list:
1502 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1503 66d1f035 René Nussbaumer
1504 66d1f035 René Nussbaumer
  return True
1505 66d1f035 René Nussbaumer
1506 66d1f035 René Nussbaumer
1507 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1508 66d1f035 René Nussbaumer
  """Does the actual power on.
1509 66d1f035 René Nussbaumer

1510 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1511 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1512 66d1f035 René Nussbaumer
                         OOB)
1513 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1514 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1515 66d1f035 René Nussbaumer
  @return: The desired exit status
1516 66d1f035 René Nussbaumer

1517 66d1f035 René Nussbaumer
  """
1518 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1519 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1520 66d1f035 René Nussbaumer
             " manually if needed")
1521 66d1f035 René Nussbaumer
1522 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1523 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1524 66d1f035 René Nussbaumer
1525 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1526 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1527 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1528 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1529 66d1f035 René Nussbaumer
1530 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1531 66d1f035 René Nussbaumer
1532 66d1f035 René Nussbaumer
1533 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1534 66d1f035 René Nussbaumer
  """Does the actual power off.
1535 66d1f035 René Nussbaumer

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

1541 66d1f035 René Nussbaumer
  """
1542 3e0ed18c René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False, no_remember=True):
1543 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1544 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1545 66d1f035 René Nussbaumer
1546 66d1f035 René Nussbaumer
  if not node_list:
1547 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1548 66d1f035 René Nussbaumer
1549 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1550 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1551 66d1f035 René Nussbaumer
  else:
1552 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1553 66d1f035 René Nussbaumer
1554 66d1f035 René Nussbaumer
1555 fbde16f0 Helga Velroyen
def Epo(opts, args, qcl=None, _on_fn=_EpoOn, _off_fn=_EpoOff,
1556 1ca7b773 Michael Hanselmann
        _confirm_fn=ConfirmOperation,
1557 1ca7b773 Michael Hanselmann
        _stdout_fn=ToStdout, _stderr_fn=ToStderr):
1558 66d1f035 René Nussbaumer
  """EPO operations.
1559 66d1f035 René Nussbaumer

1560 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1561 66d1f035 René Nussbaumer
  @type args: list
1562 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1563 66d1f035 René Nussbaumer
  @rtype: int
1564 66d1f035 René Nussbaumer
  @return: the desired exit code
1565 66d1f035 René Nussbaumer

1566 66d1f035 René Nussbaumer
  """
1567 66d1f035 René Nussbaumer
  if opts.groups and opts.show_all:
1568 1ca7b773 Michael Hanselmann
    _stderr_fn("Only one of --groups or --all are allowed")
1569 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1570 66d1f035 René Nussbaumer
  elif args and opts.show_all:
1571 1ca7b773 Michael Hanselmann
    _stderr_fn("Arguments in combination with --all are not allowed")
1572 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1573 66d1f035 René Nussbaumer
1574 bc57fa8d Helga Velroyen
  if qcl is None:
1575 bc57fa8d Helga Velroyen
    # Query client
1576 2af8b9c9 Klaus Aehlig
    qcl = GetClient()
1577 66d1f035 René Nussbaumer
1578 66d1f035 René Nussbaumer
  if opts.groups:
1579 1ca7b773 Michael Hanselmann
    node_query_list = \
1580 fbde16f0 Helga Velroyen
      itertools.chain(*qcl.QueryGroups(args, ["node_list"], False))
1581 66d1f035 René Nussbaumer
  else:
1582 66d1f035 René Nussbaumer
    node_query_list = args
1583 66d1f035 René Nussbaumer
1584 bc57fa8d Helga Velroyen
  result = qcl.QueryNodes(node_query_list, ["name", "master", "pinst_list",
1585 bc57fa8d Helga Velroyen
                                            "sinst_list", "powered", "offline"],
1586 bc57fa8d Helga Velroyen
                          False)
1587 45a36f36 Michael Hanselmann
1588 45a36f36 Michael Hanselmann
  all_nodes = map(compat.fst, result)
1589 66d1f035 René Nussbaumer
  node_list = []
1590 66d1f035 René Nussbaumer
  inst_map = {}
1591 3008f56c Iustin Pop
  for (node, master, pinsts, sinsts, powered, offline) in result:
1592 66d1f035 René Nussbaumer
    if not offline:
1593 66d1f035 René Nussbaumer
      for inst in (pinsts + sinsts):
1594 66d1f035 René Nussbaumer
        if inst in inst_map:
1595 66d1f035 René Nussbaumer
          if not master:
1596 66d1f035 René Nussbaumer
            inst_map[inst].add(node)
1597 66d1f035 René Nussbaumer
        elif master:
1598 66d1f035 René Nussbaumer
          inst_map[inst] = set()
1599 66d1f035 René Nussbaumer
        else:
1600 66d1f035 René Nussbaumer
          inst_map[inst] = set([node])
1601 66d1f035 René Nussbaumer
1602 66d1f035 René Nussbaumer
    if master and opts.on:
1603 66d1f035 René Nussbaumer
      # We ignore the master for turning on the machines, in fact we are
1604 66d1f035 René Nussbaumer
      # already operating on the master at this point :)
1605 66d1f035 René Nussbaumer
      continue
1606 66d1f035 René Nussbaumer
    elif master and not opts.show_all:
1607 1ca7b773 Michael Hanselmann
      _stderr_fn("%s is the master node, please do a master-failover to another"
1608 1ca7b773 Michael Hanselmann
                 " node not affected by the EPO or use --all if you intend to"
1609 1ca7b773 Michael Hanselmann
                 " shutdown the whole cluster", node)
1610 66d1f035 René Nussbaumer
      return constants.EXIT_FAILURE
1611 66d1f035 René Nussbaumer
    elif powered is None:
1612 1ca7b773 Michael Hanselmann
      _stdout_fn("Node %s does not support out-of-band handling, it can not be"
1613 1ca7b773 Michael Hanselmann
                 " handled in a fully automated manner", node)
1614 66d1f035 René Nussbaumer
    elif powered == opts.on:
1615 1ca7b773 Michael Hanselmann
      _stdout_fn("Node %s is already in desired power state, skipping", node)
1616 66d1f035 René Nussbaumer
    elif not offline or (offline and powered):
1617 66d1f035 René Nussbaumer
      node_list.append(node)
1618 66d1f035 René Nussbaumer
1619 1ca7b773 Michael Hanselmann
  if not (opts.force or _confirm_fn(all_nodes, "nodes", "epo")):
1620 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1621 66d1f035 René Nussbaumer
1622 66d1f035 René Nussbaumer
  if opts.on:
1623 1ca7b773 Michael Hanselmann
    return _on_fn(opts, all_nodes, node_list, inst_map)
1624 66d1f035 René Nussbaumer
  else:
1625 1ca7b773 Michael Hanselmann
    return _off_fn(opts, node_list, inst_map)
1626 1ca7b773 Michael Hanselmann
1627 66d1f035 René Nussbaumer
1628 ea9d3b40 Bernardo Dal Seno
def _GetCreateCommand(info):
1629 ea9d3b40 Bernardo Dal Seno
  buf = StringIO()
1630 ea9d3b40 Bernardo Dal Seno
  buf.write("gnt-cluster init")
1631 ea9d3b40 Bernardo Dal Seno
  PrintIPolicyCommand(buf, info["ipolicy"], False)
1632 ea9d3b40 Bernardo Dal Seno
  buf.write(" ")
1633 ea9d3b40 Bernardo Dal Seno
  buf.write(info["name"])
1634 ea9d3b40 Bernardo Dal Seno
  return buf.getvalue()
1635 ea9d3b40 Bernardo Dal Seno
1636 ea9d3b40 Bernardo Dal Seno
1637 ea9d3b40 Bernardo Dal Seno
def ShowCreateCommand(opts, args):
1638 ea9d3b40 Bernardo Dal Seno
  """Shows the command that can be used to re-create the cluster.
1639 ea9d3b40 Bernardo Dal Seno

1640 ea9d3b40 Bernardo Dal Seno
  Currently it works only for ipolicy specs.
1641 ea9d3b40 Bernardo Dal Seno

1642 ea9d3b40 Bernardo Dal Seno
  """
1643 2af8b9c9 Klaus Aehlig
  cl = GetClient()
1644 ea9d3b40 Bernardo Dal Seno
  result = cl.QueryClusterInfo()
1645 ea9d3b40 Bernardo Dal Seno
  ToStdout(_GetCreateCommand(result))
1646 ea9d3b40 Bernardo Dal Seno
1647 ea9d3b40 Bernardo Dal Seno
1648 c51ffffe Klaus Aehlig
def _RunCommandAndReport(cmd):
1649 c51ffffe Klaus Aehlig
  """Run a command and report its output, iff it failed.
1650 c51ffffe Klaus Aehlig

1651 c51ffffe Klaus Aehlig
  @param cmd: the command to execute
1652 c51ffffe Klaus Aehlig
  @type cmd: list
1653 c51ffffe Klaus Aehlig
  @rtype: bool
1654 c51ffffe Klaus Aehlig
  @return: False, if the execution failed.
1655 c51ffffe Klaus Aehlig

1656 c51ffffe Klaus Aehlig
  """
1657 c51ffffe Klaus Aehlig
  result = utils.RunCmd(cmd)
1658 c51ffffe Klaus Aehlig
  if result.failed:
1659 c51ffffe Klaus Aehlig
    ToStderr("Command %s failed: %s; Output %s" %
1660 c51ffffe Klaus Aehlig
             (cmd, result.fail_reason, result.output))
1661 c51ffffe Klaus Aehlig
    return False
1662 c51ffffe Klaus Aehlig
  return True
1663 c51ffffe Klaus Aehlig
1664 c51ffffe Klaus Aehlig
1665 c51ffffe Klaus Aehlig
def _VerifyCommand(cmd):
1666 c51ffffe Klaus Aehlig
  """Verify that a given command succeeds on all online nodes.
1667 c51ffffe Klaus Aehlig

1668 c51ffffe Klaus Aehlig
  As this function is intended to run during upgrades, it
1669 c51ffffe Klaus Aehlig
  is implemented in such a way that it still works, if all Ganeti
1670 c51ffffe Klaus Aehlig
  daemons are down.
1671 c51ffffe Klaus Aehlig

1672 c51ffffe Klaus Aehlig
  @param cmd: the command to execute
1673 c51ffffe Klaus Aehlig
  @type cmd: list
1674 c51ffffe Klaus Aehlig
  @rtype: list
1675 c51ffffe Klaus Aehlig
  @return: the list of node names that are online where
1676 c51ffffe Klaus Aehlig
      the command failed.
1677 c51ffffe Klaus Aehlig

1678 c51ffffe Klaus Aehlig
  """
1679 c51ffffe Klaus Aehlig
  command = utils.text.ShellQuoteArgs([str(val) for val in cmd])
1680 c51ffffe Klaus Aehlig
1681 c51ffffe Klaus Aehlig
  nodes = ssconf.SimpleStore().GetOnlineNodeList()
1682 c51ffffe Klaus Aehlig
  master_node = ssconf.SimpleStore().GetMasterNode()
1683 c51ffffe Klaus Aehlig
  cluster_name = ssconf.SimpleStore().GetClusterName()
1684 c51ffffe Klaus Aehlig
1685 c51ffffe Klaus Aehlig
  # If master node is in 'nodes', make sure master node is at list end
1686 c51ffffe Klaus Aehlig
  if master_node in nodes:
1687 c51ffffe Klaus Aehlig
    nodes.remove(master_node)
1688 c51ffffe Klaus Aehlig
    nodes.append(master_node)
1689 c51ffffe Klaus Aehlig
1690 c51ffffe Klaus Aehlig
  failed = []
1691 c51ffffe Klaus Aehlig
1692 c51ffffe Klaus Aehlig
  srun = ssh.SshRunner(cluster_name=cluster_name)
1693 c51ffffe Klaus Aehlig
  for name in nodes:
1694 c51ffffe Klaus Aehlig
    result = srun.Run(name, constants.SSH_LOGIN_USER, command)
1695 c51ffffe Klaus Aehlig
    if result.exit_code != 0:
1696 c51ffffe Klaus Aehlig
      failed.append(name)
1697 c51ffffe Klaus Aehlig
1698 c51ffffe Klaus Aehlig
  return failed
1699 c51ffffe Klaus Aehlig
1700 c51ffffe Klaus Aehlig
1701 c51ffffe Klaus Aehlig
def _VerifyVersionInstalled(versionstring):
1702 c51ffffe Klaus Aehlig
  """Verify that the given version of ganeti is installed on all online nodes.
1703 c51ffffe Klaus Aehlig

1704 c51ffffe Klaus Aehlig
  Do nothing, if this is the case, otherwise print an appropriate
1705 c51ffffe Klaus Aehlig
  message to stderr.
1706 c51ffffe Klaus Aehlig

1707 c51ffffe Klaus Aehlig
  @param versionstring: the version to check for
1708 c51ffffe Klaus Aehlig
  @type versionstring: string
1709 c51ffffe Klaus Aehlig
  @rtype: bool
1710 c51ffffe Klaus Aehlig
  @return: True, if the version is installed on all online nodes
1711 c51ffffe Klaus Aehlig

1712 c51ffffe Klaus Aehlig
  """
1713 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand(["test", "-d",
1714 c51ffffe Klaus Aehlig
                             os.path.join(pathutils.PKGLIBDIR, versionstring)])
1715 c51ffffe Klaus Aehlig
  if badnodes:
1716 c51ffffe Klaus Aehlig
    ToStderr("Ganeti version %s not installed on nodes %s"
1717 c51ffffe Klaus Aehlig
             % (versionstring, ", ".join(badnodes)))
1718 c51ffffe Klaus Aehlig
    return False
1719 c51ffffe Klaus Aehlig
1720 c51ffffe Klaus Aehlig
  return True
1721 c51ffffe Klaus Aehlig
1722 c51ffffe Klaus Aehlig
1723 c51ffffe Klaus Aehlig
def _GetRunning():
1724 c51ffffe Klaus Aehlig
  """Determine the list of running jobs.
1725 c51ffffe Klaus Aehlig

1726 c51ffffe Klaus Aehlig
  @rtype: list
1727 c51ffffe Klaus Aehlig
  @return: the number of jobs still running
1728 c51ffffe Klaus Aehlig

1729 c51ffffe Klaus Aehlig
  """
1730 c51ffffe Klaus Aehlig
  cl = GetClient()
1731 c51ffffe Klaus Aehlig
  qfilter = qlang.MakeSimpleFilter("status",
1732 c51ffffe Klaus Aehlig
                                   frozenset([constants.JOB_STATUS_RUNNING]))
1733 c51ffffe Klaus Aehlig
  return len(cl.Query(constants.QR_JOB, [], qfilter).data)
1734 c51ffffe Klaus Aehlig
1735 c51ffffe Klaus Aehlig
1736 c51ffffe Klaus Aehlig
def _SetGanetiVersion(versionstring):
1737 c51ffffe Klaus Aehlig
  """Set the active version of ganeti to the given versionstring
1738 c51ffffe Klaus Aehlig

1739 c51ffffe Klaus Aehlig
  @type versionstring: string
1740 c51ffffe Klaus Aehlig
  @rtype: list
1741 c51ffffe Klaus Aehlig
  @return: the list of nodes where the version change failed
1742 c51ffffe Klaus Aehlig

1743 c51ffffe Klaus Aehlig
  """
1744 c51ffffe Klaus Aehlig
  failed = []
1745 645bba3a Klaus Aehlig
  if constants.HAS_GNU_LN:
1746 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1747 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", "-T",
1748 645bba3a Klaus Aehlig
         os.path.join(pathutils.PKGLIBDIR, versionstring),
1749 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/lib")]))
1750 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1751 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", "-T",
1752 645bba3a Klaus Aehlig
         os.path.join(pathutils.SHAREDIR, versionstring),
1753 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/share")]))
1754 645bba3a Klaus Aehlig
  else:
1755 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1756 645bba3a Klaus Aehlig
        ["rm", "-f", os.path.join(pathutils.SYSCONFDIR, "ganeti/lib")]))
1757 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1758 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", os.path.join(pathutils.PKGLIBDIR, versionstring),
1759 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/lib")]))
1760 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1761 645bba3a Klaus Aehlig
        ["rm", "-f", os.path.join(pathutils.SYSCONFDIR, "ganeti/share")]))
1762 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1763 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", os.path.join(pathutils.SHAREDIR, versionstring),
1764 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/share")]))
1765 c51ffffe Klaus Aehlig
  return list(set(failed))
1766 c51ffffe Klaus Aehlig
1767 c51ffffe Klaus Aehlig
1768 c51ffffe Klaus Aehlig
def _ExecuteCommands(fns):
1769 c51ffffe Klaus Aehlig
  """Execute a list of functions, in reverse order.
1770 c51ffffe Klaus Aehlig

1771 c51ffffe Klaus Aehlig
  @type fns: list of functions.
1772 c51ffffe Klaus Aehlig
  @param fns: the functions to be executed.
1773 c51ffffe Klaus Aehlig

1774 c51ffffe Klaus Aehlig
  """
1775 c51ffffe Klaus Aehlig
  for fn in reversed(fns):
1776 c51ffffe Klaus Aehlig
    fn()
1777 c51ffffe Klaus Aehlig
1778 c51ffffe Klaus Aehlig
1779 16e81432 Klaus Aehlig
def _GetConfigVersion():
1780 16e81432 Klaus Aehlig
  """Determine the version the configuration file currently has.
1781 16e81432 Klaus Aehlig

1782 16e81432 Klaus Aehlig
  @rtype: tuple or None
1783 16e81432 Klaus Aehlig
  @return: (major, minor, revision) if the version can be determined,
1784 16e81432 Klaus Aehlig
      None otherwise
1785 16e81432 Klaus Aehlig

1786 16e81432 Klaus Aehlig
  """
1787 16e81432 Klaus Aehlig
  config_data = serializer.LoadJson(utils.ReadFile(pathutils.CLUSTER_CONF_FILE))
1788 16e81432 Klaus Aehlig
  try:
1789 16e81432 Klaus Aehlig
    config_version = config_data["version"]
1790 16e81432 Klaus Aehlig
  except KeyError:
1791 16e81432 Klaus Aehlig
    return None
1792 16e81432 Klaus Aehlig
  return utils.SplitVersion(config_version)
1793 16e81432 Klaus Aehlig
1794 16e81432 Klaus Aehlig
1795 36cfb584 Klaus Aehlig
def _ReadIntentToUpgrade():
1796 36cfb584 Klaus Aehlig
  """Read the file documenting the intent to upgrade the cluster.
1797 36cfb584 Klaus Aehlig

1798 4a67e386 Klaus Aehlig
  @rtype: (string, string) or (None, None)
1799 4a67e386 Klaus Aehlig
  @return: (old version, version to upgrade to), if the file exists,
1800 4a67e386 Klaus Aehlig
      and (None, None) otherwise.
1801 36cfb584 Klaus Aehlig

1802 36cfb584 Klaus Aehlig
  """
1803 36cfb584 Klaus Aehlig
  if not os.path.isfile(pathutils.INTENT_TO_UPGRADE):
1804 4a67e386 Klaus Aehlig
    return (None, None)
1805 36cfb584 Klaus Aehlig
1806 36cfb584 Klaus Aehlig
  contentstring = utils.ReadFile(pathutils.INTENT_TO_UPGRADE)
1807 36cfb584 Klaus Aehlig
  contents = utils.UnescapeAndSplit(contentstring)
1808 3cac836b Klaus Aehlig
  if len(contents) != 3:
1809 36cfb584 Klaus Aehlig
    # file syntactically mal-formed
1810 4a67e386 Klaus Aehlig
    return (None, None)
1811 4a67e386 Klaus Aehlig
  return (contents[0], contents[1])
1812 36cfb584 Klaus Aehlig
1813 36cfb584 Klaus Aehlig
1814 3b31c9da Klaus Aehlig
def _WriteIntentToUpgrade(version):
1815 3b31c9da Klaus Aehlig
  """Write file documenting the intent to upgrade the cluster.
1816 3b31c9da Klaus Aehlig

1817 3b31c9da Klaus Aehlig
  @type version: string
1818 3b31c9da Klaus Aehlig
  @param version: the version we intent to upgrade to
1819 3b31c9da Klaus Aehlig

1820 3b31c9da Klaus Aehlig
  """
1821 3b31c9da Klaus Aehlig
  utils.WriteFile(pathutils.INTENT_TO_UPGRADE,
1822 3cac836b Klaus Aehlig
                  data=utils.EscapeAndJoin([constants.RELEASE_VERSION, version,
1823 3cac836b Klaus Aehlig
                                            "%d" % os.getpid()]))
1824 3b31c9da Klaus Aehlig
1825 3b31c9da Klaus Aehlig
1826 6c2a735a Klaus Aehlig
def _UpgradeBeforeConfigurationChange(versionstring):
1827 c51ffffe Klaus Aehlig
  """
1828 6c2a735a Klaus Aehlig
  Carry out all the tasks necessary for an upgrade that happen before
1829 6c2a735a Klaus Aehlig
  the configuration file, or Ganeti version, changes.
1830 c51ffffe Klaus Aehlig

1831 6c2a735a Klaus Aehlig
  @type versionstring: string
1832 6c2a735a Klaus Aehlig
  @param versionstring: the version to upgrade to
1833 6c2a735a Klaus Aehlig
  @rtype: (bool, list)
1834 6c2a735a Klaus Aehlig
  @return: tuple of a bool indicating success and a list of rollback tasks
1835 c51ffffe Klaus Aehlig

1836 6c2a735a Klaus Aehlig
  """
1837 c51ffffe Klaus Aehlig
  rollback = []
1838 c51ffffe Klaus Aehlig
1839 c51ffffe Klaus Aehlig
  if not _VerifyVersionInstalled(versionstring):
1840 6c2a735a Klaus Aehlig
    return (False, rollback)
1841 c51ffffe Klaus Aehlig
1842 3b31c9da Klaus Aehlig
  _WriteIntentToUpgrade(versionstring)
1843 3b31c9da Klaus Aehlig
  rollback.append(
1844 3b31c9da Klaus Aehlig
    lambda: utils.RunCmd(["rm", "-f", pathutils.INTENT_TO_UPGRADE]))
1845 c51ffffe Klaus Aehlig
1846 c51ffffe Klaus Aehlig
  ToStdout("Draining queue")
1847 c51ffffe Klaus Aehlig
  client = GetClient()
1848 c51ffffe Klaus Aehlig
  client.SetQueueDrainFlag(True)
1849 c51ffffe Klaus Aehlig
1850 c51ffffe Klaus Aehlig
  rollback.append(lambda: GetClient().SetQueueDrainFlag(False))
1851 c51ffffe Klaus Aehlig
1852 c51ffffe Klaus Aehlig
  if utils.SimpleRetry(0, _GetRunning,
1853 c51ffffe Klaus Aehlig
                       constants.UPGRADE_QUEUE_POLL_INTERVAL,
1854 c51ffffe Klaus Aehlig
                       constants.UPGRADE_QUEUE_DRAIN_TIMEOUT):
1855 c51ffffe Klaus Aehlig
    ToStderr("Failed to completely empty the queue.")
1856 6c2a735a Klaus Aehlig
    return (False, rollback)
1857 c51ffffe Klaus Aehlig
1858 c51ffffe Klaus Aehlig
  ToStdout("Stopping daemons on master node.")
1859 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport([pathutils.DAEMON_UTIL, "stop-all"]):
1860 6c2a735a Klaus Aehlig
    return (False, rollback)
1861 c51ffffe Klaus Aehlig
1862 c51ffffe Klaus Aehlig
  if not _VerifyVersionInstalled(versionstring):
1863 c51ffffe Klaus Aehlig
    utils.RunCmd([pathutils.DAEMON_UTIL, "start-all"])
1864 6c2a735a Klaus Aehlig
    return (False, rollback)
1865 c51ffffe Klaus Aehlig
1866 c51ffffe Klaus Aehlig
  ToStdout("Stopping daemons everywhere.")
1867 c51ffffe Klaus Aehlig
  rollback.append(lambda: _VerifyCommand([pathutils.DAEMON_UTIL, "start-all"]))
1868 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "stop-all"])
1869 c51ffffe Klaus Aehlig
  if badnodes:
1870 c51ffffe Klaus Aehlig
    ToStderr("Failed to stop daemons on %s." % (", ".join(badnodes),))
1871 6c2a735a Klaus Aehlig
    return (False, rollback)
1872 c51ffffe Klaus Aehlig
1873 c51ffffe Klaus Aehlig
  backuptar = os.path.join(pathutils.LOCALSTATEDIR,
1874 c51ffffe Klaus Aehlig
                           "lib/ganeti%d.tar" % time.time())
1875 c51ffffe Klaus Aehlig
  ToStdout("Backing up configuration as %s" % backuptar)
1876 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["tar", "cf", backuptar,
1877 c51ffffe Klaus Aehlig
                               pathutils.DATA_DIR]):
1878 6c2a735a Klaus Aehlig
    return (False, rollback)
1879 6c2a735a Klaus Aehlig
1880 6c2a735a Klaus Aehlig
  return (True, rollback)
1881 c51ffffe Klaus Aehlig
1882 6c2a735a Klaus Aehlig
1883 c09c495c Klaus Aehlig
def _VersionSpecificDowngrade():
1884 c09c495c Klaus Aehlig
  """
1885 c09c495c Klaus Aehlig
  Perform any additional downrade tasks that are version specific
1886 c09c495c Klaus Aehlig
  and need to be done just after the configuration downgrade. This
1887 c09c495c Klaus Aehlig
  function needs to be idempotent, so that it can be redone if the
1888 c09c495c Klaus Aehlig
  downgrade procedure gets interrupted after changing the
1889 c09c495c Klaus Aehlig
  configuration.
1890 c09c495c Klaus Aehlig

1891 c09c495c Klaus Aehlig
  Note that this function has to be reset with every version bump.
1892 c09c495c Klaus Aehlig

1893 c09c495c Klaus Aehlig
  @return: True upon success
1894 c09c495c Klaus Aehlig
  """
1895 c09c495c Klaus Aehlig
  ToStdout("Performing version-specific downgrade tasks.")
1896 c09c495c Klaus Aehlig
  return True
1897 c09c495c Klaus Aehlig
1898 c09c495c Klaus Aehlig
1899 6c2a735a Klaus Aehlig
def _SwitchVersionAndConfig(versionstring, downgrade):
1900 6c2a735a Klaus Aehlig
  """
1901 6c2a735a Klaus Aehlig
  Switch to the new Ganeti version and change the configuration,
1902 6c2a735a Klaus Aehlig
  in correct order.
1903 6c2a735a Klaus Aehlig

1904 6c2a735a Klaus Aehlig
  @type versionstring: string
1905 6c2a735a Klaus Aehlig
  @param versionstring: the version to change to
1906 6c2a735a Klaus Aehlig
  @type downgrade: bool
1907 6c2a735a Klaus Aehlig
  @param downgrade: True, if the configuration should be downgraded
1908 6c2a735a Klaus Aehlig
  @rtype: (bool, list)
1909 6c2a735a Klaus Aehlig
  @return: tupe of a bool indicating success, and a list of
1910 6c2a735a Klaus Aehlig
      additional rollback tasks
1911 6c2a735a Klaus Aehlig

1912 6c2a735a Klaus Aehlig
  """
1913 6c2a735a Klaus Aehlig
  rollback = []
1914 c51ffffe Klaus Aehlig
  if downgrade:
1915 c51ffffe Klaus Aehlig
    ToStdout("Downgrading configuration")
1916 c51ffffe Klaus Aehlig
    if not _RunCommandAndReport([pathutils.CFGUPGRADE, "--downgrade", "-f"]):
1917 6c2a735a Klaus Aehlig
      return (False, rollback)
1918 c09c495c Klaus Aehlig
    # Note: version specific downgrades need to be done before switching
1919 c09c495c Klaus Aehlig
    # binaries, so that we still have the knowledgeable binary if the downgrade
1920 c09c495c Klaus Aehlig
    # process gets interrupted at this point.
1921 c09c495c Klaus Aehlig
    if not _VersionSpecificDowngrade():
1922 c09c495c Klaus Aehlig
      return (False, rollback)
1923 c51ffffe Klaus Aehlig
1924 c51ffffe Klaus Aehlig
  # Configuration change is the point of no return. From then onwards, it is
1925 c51ffffe Klaus Aehlig
  # safer to push through the up/dowgrade than to try to roll it back.
1926 c51ffffe Klaus Aehlig
1927 c51ffffe Klaus Aehlig
  ToStdout("Switching to version %s on all nodes" % versionstring)
1928 c51ffffe Klaus Aehlig
  rollback.append(lambda: _SetGanetiVersion(constants.DIR_VERSION))
1929 c51ffffe Klaus Aehlig
  badnodes = _SetGanetiVersion(versionstring)
1930 c51ffffe Klaus Aehlig
  if badnodes:
1931 c51ffffe Klaus Aehlig
    ToStderr("Failed to switch to Ganeti version %s on nodes %s"
1932 c51ffffe Klaus Aehlig
             % (versionstring, ", ".join(badnodes)))
1933 c51ffffe Klaus Aehlig
    if not downgrade:
1934 6c2a735a Klaus Aehlig
      return (False, rollback)
1935 c51ffffe Klaus Aehlig
1936 c51ffffe Klaus Aehlig
  # Now that we have changed to the new version of Ganeti we should
1937 c51ffffe Klaus Aehlig
  # not communicate over luxi any more, as luxi might have changed in
1938 c51ffffe Klaus Aehlig
  # incompatible ways. Therefore, manually call the corresponding ganeti
1939 c51ffffe Klaus Aehlig
  # commands using their canonical (version independent) path.
1940 c51ffffe Klaus Aehlig
1941 c51ffffe Klaus Aehlig
  if not downgrade:
1942 c51ffffe Klaus Aehlig
    ToStdout("Upgrading configuration")
1943 c51ffffe Klaus Aehlig
    if not _RunCommandAndReport([pathutils.CFGUPGRADE, "-f"]):
1944 6c2a735a Klaus Aehlig
      return (False, rollback)
1945 6c2a735a Klaus Aehlig
1946 6c2a735a Klaus Aehlig
  return (True, rollback)
1947 6c2a735a Klaus Aehlig
1948 6c2a735a Klaus Aehlig
1949 4a67e386 Klaus Aehlig
def _UpgradeAfterConfigurationChange(oldversion):
1950 6c2a735a Klaus Aehlig
  """
1951 6c2a735a Klaus Aehlig
  Carry out the upgrade actions necessary after switching to the new
1952 6c2a735a Klaus Aehlig
  Ganeti version and updating the configuration.
1953 6c2a735a Klaus Aehlig

1954 6c2a735a Klaus Aehlig
  As this part is run at a time where the new version of Ganeti is already
1955 6c2a735a Klaus Aehlig
  running, no communication should happen via luxi, as this is not a stable
1956 6c2a735a Klaus Aehlig
  interface. Also, as the configuration change is the point of no return,
1957 6c2a735a Klaus Aehlig
  all actions are pushed trough, even if some of them fail.
1958 6c2a735a Klaus Aehlig

1959 4a67e386 Klaus Aehlig
  @param oldversion: the version the upgrade started from
1960 4a67e386 Klaus Aehlig
  @type oldversion: string
1961 6c2a735a Klaus Aehlig
  @rtype: int
1962 6c2a735a Klaus Aehlig
  @return: the intended return value
1963 6c2a735a Klaus Aehlig

1964 6c2a735a Klaus Aehlig
  """
1965 6c2a735a Klaus Aehlig
  returnvalue = 0
1966 c51ffffe Klaus Aehlig
1967 c51ffffe Klaus Aehlig
  ToStdout("Ensuring directories everywhere.")
1968 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.ENSURE_DIRS])
1969 c51ffffe Klaus Aehlig
  if badnodes:
1970 c51ffffe Klaus Aehlig
    ToStderr("Warning: failed to ensure directories on %s." %
1971 c51ffffe Klaus Aehlig
             (", ".join(badnodes)))
1972 c51ffffe Klaus Aehlig
    returnvalue = 1
1973 c51ffffe Klaus Aehlig
1974 401b773e Klaus Aehlig
  ToStdout("Starting daemons everywhere.")
1975 401b773e Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "start-all"])
1976 401b773e Klaus Aehlig
  if badnodes:
1977 401b773e Klaus Aehlig
    ToStderr("Warning: failed to start daemons on %s." % (", ".join(badnodes),))
1978 401b773e Klaus Aehlig
    returnvalue = 1
1979 401b773e Klaus Aehlig
1980 c51ffffe Klaus Aehlig
  ToStdout("Redistributing the configuration.")
1981 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "redist-conf", "--yes-do-it"]):
1982 c51ffffe Klaus Aehlig
    returnvalue = 1
1983 c51ffffe Klaus Aehlig
1984 c51ffffe Klaus Aehlig
  ToStdout("Restarting daemons everywhere.")
1985 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "stop-all"])
1986 c51ffffe Klaus Aehlig
  badnodes.extend(_VerifyCommand([pathutils.DAEMON_UTIL, "start-all"]))
1987 c51ffffe Klaus Aehlig
  if badnodes:
1988 c51ffffe Klaus Aehlig
    ToStderr("Warning: failed to start daemons on %s." %
1989 c51ffffe Klaus Aehlig
             (", ".join(list(set(badnodes))),))
1990 c51ffffe Klaus Aehlig
    returnvalue = 1
1991 c51ffffe Klaus Aehlig
1992 c51ffffe Klaus Aehlig
  ToStdout("Undraining the queue.")
1993 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "queue", "undrain"]):
1994 c51ffffe Klaus Aehlig
    returnvalue = 1
1995 c51ffffe Klaus Aehlig
1996 3b31c9da Klaus Aehlig
  _RunCommandAndReport(["rm", "-f", pathutils.INTENT_TO_UPGRADE])
1997 c51ffffe Klaus Aehlig
1998 4a67e386 Klaus Aehlig
  ToStdout("Running post-upgrade hooks")
1999 4a67e386 Klaus Aehlig
  if not _RunCommandAndReport([pathutils.POST_UPGRADE, oldversion]):
2000 4a67e386 Klaus Aehlig
    returnvalue = 1
2001 4a67e386 Klaus Aehlig
2002 c51ffffe Klaus Aehlig
  ToStdout("Verifying cluster.")
2003 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "verify"]):
2004 c51ffffe Klaus Aehlig
    returnvalue = 1
2005 c51ffffe Klaus Aehlig
2006 c51ffffe Klaus Aehlig
  return returnvalue
2007 c51ffffe Klaus Aehlig
2008 c51ffffe Klaus Aehlig
2009 6c2a735a Klaus Aehlig
def UpgradeGanetiCommand(opts, args):
2010 6c2a735a Klaus Aehlig
  """Upgrade a cluster to a new ganeti version.
2011 6c2a735a Klaus Aehlig

2012 6c2a735a Klaus Aehlig
  @param opts: the command line options selected by the user
2013 6c2a735a Klaus Aehlig
  @type args: list
2014 6c2a735a Klaus Aehlig
  @param args: should be an empty list
2015 6c2a735a Klaus Aehlig
  @rtype: int
2016 6c2a735a Klaus Aehlig
  @return: the desired exit code
2017 6c2a735a Klaus Aehlig

2018 6c2a735a Klaus Aehlig
  """
2019 6c2a735a Klaus Aehlig
  if ((not opts.resume and opts.to is None)
2020 6c2a735a Klaus Aehlig
      or (opts.resume and opts.to is not None)):
2021 6c2a735a Klaus Aehlig
    ToStderr("Precisely one of the options --to and --resume"
2022 6c2a735a Klaus Aehlig
             " has to be given")
2023 6c2a735a Klaus Aehlig
    return 1
2024 6c2a735a Klaus Aehlig
2025 4a67e386 Klaus Aehlig
  oldversion = constants.RELEASE_VERSION
2026 4a67e386 Klaus Aehlig
2027 6c2a735a Klaus Aehlig
  if opts.resume:
2028 6c2a735a Klaus Aehlig
    ssconf.CheckMaster(False)
2029 4a67e386 Klaus Aehlig
    oldversion, versionstring = _ReadIntentToUpgrade()
2030 6c2a735a Klaus Aehlig
    if versionstring is None:
2031 6c2a735a Klaus Aehlig
      return 0
2032 6c2a735a Klaus Aehlig
    version = utils.version.ParseVersion(versionstring)
2033 6c2a735a Klaus Aehlig
    if version is None:
2034 6c2a735a Klaus Aehlig
      return 1
2035 6c2a735a Klaus Aehlig
    configversion = _GetConfigVersion()
2036 6c2a735a Klaus Aehlig
    if configversion is None:
2037 6c2a735a Klaus Aehlig
      return 1
2038 6c2a735a Klaus Aehlig
    # If the upgrade we resume was an upgrade between compatible
2039 6c2a735a Klaus Aehlig
    # versions (like 2.10.0 to 2.10.1), the correct configversion
2040 6c2a735a Klaus Aehlig
    # does not guarantee that the config has been updated.
2041 6c2a735a Klaus Aehlig
    # However, in the case of a compatible update with the configuration
2042 6c2a735a Klaus Aehlig
    # not touched, we are running a different dirversion with the same
2043 6c2a735a Klaus Aehlig
    # config version.
2044 6c2a735a Klaus Aehlig
    config_already_modified = \
2045 6c2a735a Klaus Aehlig
      (utils.IsCorrectConfigVersion(version, configversion) and
2046 6c2a735a Klaus Aehlig
       not (versionstring != constants.DIR_VERSION and
2047 6c2a735a Klaus Aehlig
            configversion == (constants.CONFIG_MAJOR, constants.CONFIG_MINOR,
2048 6c2a735a Klaus Aehlig
                              constants.CONFIG_REVISION)))
2049 6c2a735a Klaus Aehlig
    if not config_already_modified:
2050 6c2a735a Klaus Aehlig
      # We have to start from the beginning; however, some daemons might have
2051 6c2a735a Klaus Aehlig
      # already been stopped, so the only way to get into a well-defined state
2052 6c2a735a Klaus Aehlig
      # is by starting all daemons again.
2053 6c2a735a Klaus Aehlig
      _VerifyCommand([pathutils.DAEMON_UTIL, "start-all"])
2054 6c2a735a Klaus Aehlig
  else:
2055 6c2a735a Klaus Aehlig
    versionstring = opts.to
2056 6c2a735a Klaus Aehlig
    config_already_modified = False
2057 6c2a735a Klaus Aehlig
    version = utils.version.ParseVersion(versionstring)
2058 6c2a735a Klaus Aehlig
    if version is None:
2059 6c2a735a Klaus Aehlig
      ToStderr("Could not parse version string %s" % versionstring)
2060 6c2a735a Klaus Aehlig
      return 1
2061 6c2a735a Klaus Aehlig
2062 6c2a735a Klaus Aehlig
  msg = utils.version.UpgradeRange(version)
2063 6c2a735a Klaus Aehlig
  if msg is not None:
2064 6c2a735a Klaus Aehlig
    ToStderr("Cannot upgrade to %s: %s" % (versionstring, msg))
2065 6c2a735a Klaus Aehlig
    return 1
2066 6c2a735a Klaus Aehlig
2067 6c2a735a Klaus Aehlig
  if not config_already_modified:
2068 6c2a735a Klaus Aehlig
    success, rollback = _UpgradeBeforeConfigurationChange(versionstring)
2069 6c2a735a Klaus Aehlig
    if not success:
2070 6c2a735a Klaus Aehlig
      _ExecuteCommands(rollback)
2071 6c2a735a Klaus Aehlig
      return 1
2072 6c2a735a Klaus Aehlig
  else:
2073 6c2a735a Klaus Aehlig
    rollback = []
2074 6c2a735a Klaus Aehlig
2075 6c2a735a Klaus Aehlig
  downgrade = utils.version.ShouldCfgdowngrade(version)
2076 6c2a735a Klaus Aehlig
2077 6c2a735a Klaus Aehlig
  success, additionalrollback =  \
2078 6c2a735a Klaus Aehlig
      _SwitchVersionAndConfig(versionstring, downgrade)
2079 6c2a735a Klaus Aehlig
  if not success:
2080 6c2a735a Klaus Aehlig
    rollback.extend(additionalrollback)
2081 6c2a735a Klaus Aehlig
    _ExecuteCommands(rollback)
2082 6c2a735a Klaus Aehlig
    return 1
2083 6c2a735a Klaus Aehlig
2084 4a67e386 Klaus Aehlig
  return _UpgradeAfterConfigurationChange(oldversion)
2085 6c2a735a Klaus Aehlig
2086 6c2a735a Klaus Aehlig
2087 a8083063 Iustin Pop
commands = {
2088 d0c8c01d Iustin Pop
  "init": (
2089 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
2090 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
2091 5a8648eb Andrea Spadaccini
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, MASTER_NETMASK_OPT,
2092 8b7b7766 Helga Velroyen
     NIC_PARAMS_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
2093 8b7b7766 Helga Velroyen
     SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT,
2094 0359e5d0 Spyros Trigazis
     DRBD_HELPER_OPT, DEFAULT_IALLOCATOR_OPT, DEFAULT_IALLOCATOR_PARAMS_OPT,
2095 0359e5d0 Spyros Trigazis
     PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT, NODE_PARAMS_OPT,
2096 0359e5d0 Spyros Trigazis
     GLOBAL_SHARED_FILEDIR_OPT, USE_EXTERNAL_MIP_SCRIPT, DISK_PARAMS_OPT,
2097 0359e5d0 Spyros Trigazis
     HV_STATE_OPT, DISK_STATE_OPT, ENABLED_DISK_TEMPLATES_OPT,
2098 d3e6fd0e Santi Raffa
     IPOLICY_STD_SPECS_OPT, GLOBAL_GLUSTER_FILEDIR_OPT]
2099 8b7b7766 Helga Velroyen
     + INSTANCE_POLICY_OPTS + SPLIT_ISPECS_OPTS,
2100 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
2101 d0c8c01d Iustin Pop
  "destroy": (
2102 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
2103 6ea815cf Iustin Pop
    "", "Destroy cluster"),
2104 d0c8c01d Iustin Pop
  "rename": (
2105 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
2106 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
2107 6ea815cf Iustin Pop
    "<new_name>",
2108 6ea815cf Iustin Pop
    "Renames the cluster"),
2109 d0c8c01d Iustin Pop
  "redist-conf": (
2110 0c455e40 Klaus Aehlig
    RedistributeConfig, ARGS_NONE, SUBMIT_OPTS +
2111 0c455e40 Klaus Aehlig
    [DRY_RUN_OPT, PRIORITY_OPT, FORCE_DISTRIBUTION],
2112 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
2113 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
2114 d0c8c01d Iustin Pop
  "verify": (
2115 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
2116 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
2117 93f2399e Andrea Spadaccini
     DRY_RUN_OPT, PRIORITY_OPT, NODEGROUP_OPT, IGNORE_ERRORS_OPT],
2118 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
2119 d0c8c01d Iustin Pop
  "verify-disks": (
2120 aa06f8c6 Michael Hanselmann
    VerifyDisks, ARGS_NONE, [PRIORITY_OPT],
2121 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
2122 d0c8c01d Iustin Pop
  "repair-disk-sizes": (
2123 aa06f8c6 Michael Hanselmann
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
2124 eb5ac108 Michael Hanselmann
    "[instance...]", "Updates mismatches in recorded disk sizes"),
2125 d0c8c01d Iustin Pop
  "master-failover": (
2126 6022a419 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT, FORCE_FAILOVER],
2127 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
2128 d0c8c01d Iustin Pop
  "master-ping": (
2129 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
2130 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
2131 d0c8c01d Iustin Pop
  "version": (
2132 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
2133 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
2134 d0c8c01d Iustin Pop
  "getmaster": (
2135 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
2136 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
2137 d0c8c01d Iustin Pop
  "copyfile": (
2138 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
2139 b6e88032 Michael Hanselmann
    [NODE_LIST_OPT, USE_REPL_NET_OPT, NODEGROUP_OPT],
2140 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
2141 d0c8c01d Iustin Pop
  "command": (
2142 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
2143 d5b031dc Michael Hanselmann
    [NODE_LIST_OPT, NODEGROUP_OPT, SHOW_MACHINE_OPT, FAILURE_ONLY_OPT],
2144 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
2145 d0c8c01d Iustin Pop
  "info": (
2146 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
2147 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
2148 d0c8c01d Iustin Pop
  "list-tags": (
2149 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
2150 d0c8c01d Iustin Pop
  "add-tags": (
2151 d6cd74dd Klaus Aehlig
    AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
2152 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
2153 d0c8c01d Iustin Pop
  "remove-tags": (
2154 d6cd74dd Klaus Aehlig
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT] + SUBMIT_OPTS,
2155 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
2156 d0c8c01d Iustin Pop
  "search-tags": (
2157 aa06f8c6 Michael Hanselmann
    SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "",
2158 aa06f8c6 Michael Hanselmann
    "Searches the tags on all objects on"
2159 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
2160 d0c8c01d Iustin Pop
  "queue": (
2161 6ea815cf Iustin Pop
    QueueOps,
2162 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
2163 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
2164 d0c8c01d Iustin Pop
  "watcher": (
2165 6ea815cf Iustin Pop
    WatcherOps,
2166 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
2167 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
2168 064c21f8 Iustin Pop
    [],
2169 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
2170 d0c8c01d Iustin Pop
  "modify": (
2171 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
2172 2f836021 Klaus Aehlig
    [FORCE_OPT,
2173 0fcb3314 Jose A. Lopes
     BACKEND_OPT, CP_SIZE_OPT, RQL_OPT, INSTANCE_COMMUNICATION_NETWORK_OPT,
2174 0cffcdb1 Dimitris Bliablias
     ENABLED_HV_OPT, HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT,
2175 8b7b7766 Helga Velroyen
     MASTER_NETMASK_OPT, NIC_PARAMS_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
2176 8b7b7766 Helga Velroyen
     UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT, DRBD_HELPER_OPT,
2177 0359e5d0 Spyros Trigazis
     DEFAULT_IALLOCATOR_OPT, DEFAULT_IALLOCATOR_PARAMS_OPT, RESERVED_LVS_OPT,
2178 0359e5d0 Spyros Trigazis
     DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT, NODE_PARAMS_OPT,
2179 0359e5d0 Spyros Trigazis
     USE_EXTERNAL_MIP_SCRIPT, DISK_PARAMS_OPT, HV_STATE_OPT, DISK_STATE_OPT] +
2180 0359e5d0 Spyros Trigazis
     SUBMIT_OPTS +
2181 c832f7e9 Klaus Aehlig
     [ENABLED_DISK_TEMPLATES_OPT, IPOLICY_STD_SPECS_OPT, MODIFY_ETCHOSTS_OPT] +
2182 3039e2dc Helga Velroyen
     INSTANCE_POLICY_OPTS + [GLOBAL_FILEDIR_OPT],
2183 6ea815cf Iustin Pop
    "[opts...]",
2184 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
2185 6d4a1656 Michael Hanselmann
  "renew-crypto": (
2186 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
2187 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
2188 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
2189 b6267745 Andrea Spadaccini
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT,
2190 b3cc1646 Helga Velroyen
     NEW_SPICE_CERT_OPT, SPICE_CERT_OPT, SPICE_CACERT_OPT,
2191 b3cc1646 Helga Velroyen
     NEW_NODE_CERT_OPT],
2192 6d4a1656 Michael Hanselmann
    "[opts...]",
2193 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
2194 66d1f035 René Nussbaumer
  "epo": (
2195 66d1f035 René Nussbaumer
    Epo, [ArgUnknown()],
2196 fcecea0b René Nussbaumer
    [FORCE_OPT, ON_OPT, GROUPS_OPT, ALL_OPT, OOB_TIMEOUT_OPT,
2197 cfed3b9f René Nussbaumer
     SHUTDOWN_TIMEOUT_OPT, POWER_DELAY_OPT],
2198 66d1f035 René Nussbaumer
    "[opts...] [args]",
2199 66d1f035 René Nussbaumer
    "Performs an emergency power-off on given args"),
2200 fb926117 Andrea Spadaccini
  "activate-master-ip": (
2201 fb926117 Andrea Spadaccini
    ActivateMasterIp, ARGS_NONE, [], "", "Activates the master IP"),
2202 fb926117 Andrea Spadaccini
  "deactivate-master-ip": (
2203 fb926117 Andrea Spadaccini
    DeactivateMasterIp, ARGS_NONE, [CONFIRM_OPT], "",
2204 fb926117 Andrea Spadaccini
    "Deactivates the master IP"),
2205 ea9d3b40 Bernardo Dal Seno
  "show-ispecs-cmd": (
2206 ea9d3b40 Bernardo Dal Seno
    ShowCreateCommand, ARGS_NONE, [], "",
2207 ea9d3b40 Bernardo Dal Seno
    "Show the command line to re-create the cluster"),
2208 c51ffffe Klaus Aehlig
  "upgrade": (
2209 c51ffffe Klaus Aehlig
    UpgradeGanetiCommand, ARGS_NONE, [TO_OPT, RESUME_OPT], "",
2210 c51ffffe Klaus Aehlig
    "Upgrade (or downgrade) to a new Ganeti version"),
2211 a8083063 Iustin Pop
  }
2212 a8083063 Iustin Pop
2213 6d4a1656 Michael Hanselmann
2214 c28502b1 Iustin Pop
#: dictionary with aliases for commands
2215 c28502b1 Iustin Pop
aliases = {
2216 d0c8c01d Iustin Pop
  "masterfailover": "master-failover",
2217 96897af7 Alexander Schreiber
  "show": "info",
2218 c28502b1 Iustin Pop
}
2219 c28502b1 Iustin Pop
2220 c28502b1 Iustin Pop
2221 7b3e7d41 Michael Hanselmann
def Main():
2222 7b3e7d41 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
2223 7b3e7d41 Michael Hanselmann
                     aliases=aliases)