Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 52261ad2

History | View | Annotate | Download (70.7 kB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

565 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
566 469ee405 Iustin Pop
  @type args: list
567 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
568 469ee405 Iustin Pop
      the file to be copied
569 469ee405 Iustin Pop
  @rtype: int
570 469ee405 Iustin Pop
  @return: the desired exit code
571 a8083063 Iustin Pop

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

602 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
603 469ee405 Iustin Pop
  @type args: list
604 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
605 469ee405 Iustin Pop
  @rtype: int
606 469ee405 Iustin Pop
  @return: the desired exit code
607 a8083063 Iustin Pop

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

649 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
650 469ee405 Iustin Pop
  @type args: list
651 469ee405 Iustin Pop
  @param args: should be an empty list
652 469ee405 Iustin Pop
  @rtype: int
653 469ee405 Iustin Pop
  @return: the desired exit code
654 a8083063 Iustin Pop

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

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

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

775 60975797 Iustin Pop
  @param opts: the command line options selected by the user
776 60975797 Iustin Pop
  @type args: list
777 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
778 60975797 Iustin Pop
  @rtype: int
779 60975797 Iustin Pop
  @return: the desired exit code
780 60975797 Iustin Pop

781 60975797 Iustin Pop
  """
782 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
783 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
784 60975797 Iustin Pop
785 60975797 Iustin Pop
786 4331f6cd Michael Hanselmann
@UsesRPC
787 a8083063 Iustin Pop
def MasterFailover(opts, args):
788 a8083063 Iustin Pop
  """Failover the master node.
789 a8083063 Iustin Pop

790 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
791 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
792 a8083063 Iustin Pop
  master.
793 a8083063 Iustin Pop

794 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
795 469ee405 Iustin Pop
  @type args: list
796 469ee405 Iustin Pop
  @param args: should be an empty list
797 469ee405 Iustin Pop
  @rtype: int
798 469ee405 Iustin Pop
  @return: the desired exit code
799 469ee405 Iustin Pop

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

815 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
816 4404ffad Iustin Pop
  @type args: list
817 4404ffad Iustin Pop
  @param args: should be an empty list
818 4404ffad Iustin Pop
  @rtype: int
819 4404ffad Iustin Pop
  @return: the desired exit code
820 4404ffad Iustin Pop

821 4404ffad Iustin Pop
  """
822 4404ffad Iustin Pop
  try:
823 4404ffad Iustin Pop
    cl = GetClient()
824 4404ffad Iustin Pop
    cl.QueryClusterInfo()
825 4404ffad Iustin Pop
    return 0
826 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
827 4404ffad Iustin Pop
    return 1
828 4404ffad Iustin Pop
829 4404ffad Iustin Pop
830 73415719 Iustin Pop
def SearchTags(opts, args):
831 73415719 Iustin Pop
  """Searches the tags on all the cluster.
832 73415719 Iustin Pop

833 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
834 469ee405 Iustin Pop
  @type args: list
835 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
836 469ee405 Iustin Pop
  @rtype: int
837 469ee405 Iustin Pop
  @return: the desired exit code
838 469ee405 Iustin Pop

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

853 b6267745 Andrea Spadaccini
  @type cert_filename: string
854 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
855 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
856 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
857 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
858 b6267745 Andrea Spadaccini
                             the public certificate
859 b6267745 Andrea Spadaccini
  @rtype: string
860 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
861 b6267745 Andrea Spadaccini

862 b6267745 Andrea Spadaccini
  """
863 b6267745 Andrea Spadaccini
  try:
864 b6267745 Andrea Spadaccini
    pem = utils.ReadFile(cert_filename)
865 b6267745 Andrea Spadaccini
  except IOError, err:
866 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
867 b6267745 Andrea Spadaccini
                               "Unable to read certificate: %s" % str(err))
868 b6267745 Andrea Spadaccini
869 b6267745 Andrea Spadaccini
  try:
870 b6267745 Andrea Spadaccini
    OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
871 b6267745 Andrea Spadaccini
  except Exception, err:
872 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
873 b6267745 Andrea Spadaccini
                               "Unable to load certificate: %s" % str(err))
874 b6267745 Andrea Spadaccini
875 b6267745 Andrea Spadaccini
  if verify_private_key:
876 b6267745 Andrea Spadaccini
    try:
877 b6267745 Andrea Spadaccini
      OpenSSL.crypto.load_privatekey(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 private key: %s" % str(err))
881 b6267745 Andrea Spadaccini
882 b6267745 Andrea Spadaccini
  return pem
883 b6267745 Andrea Spadaccini
884 b6267745 Andrea Spadaccini
885 5ae4945a Iustin Pop
def _RenewCrypto(new_cluster_cert, new_rapi_cert, # pylint: disable=R0911
886 b6267745 Andrea Spadaccini
                 rapi_cert_filename, new_spice_cert, spice_cert_filename,
887 b6267745 Andrea Spadaccini
                 spice_cacert_filename, new_confd_hmac_key, new_cds,
888 b3cc1646 Helga Velroyen
                 cds_filename, force, new_node_cert):
889 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
890 6d4a1656 Michael Hanselmann

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

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

1019 6d4a1656 Michael Hanselmann
  """
1020 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
1021 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
1022 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
1023 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
1024 b6267745 Andrea Spadaccini
                      opts.spice_cert,
1025 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
1026 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
1027 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
1028 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
1029 b3cc1646 Helga Velroyen
                      opts.force,
1030 b3cc1646 Helga Velroyen
                      opts.new_node_cert)
1031 6d4a1656 Michael Hanselmann
1032 6d4a1656 Michael Hanselmann
1033 c121d42f Helga Velroyen
def _GetEnabledDiskTemplates(opts):
1034 c121d42f Helga Velroyen
  """Determine the list of enabled disk templates.
1035 c121d42f Helga Velroyen

1036 c121d42f Helga Velroyen
  """
1037 c121d42f Helga Velroyen
  if opts.enabled_disk_templates:
1038 c121d42f Helga Velroyen
    return opts.enabled_disk_templates.split(",")
1039 c121d42f Helga Velroyen
  else:
1040 c121d42f Helga Velroyen
    return None
1041 c121d42f Helga Velroyen
1042 c121d42f Helga Velroyen
1043 c121d42f Helga Velroyen
def _GetVgName(opts, enabled_disk_templates):
1044 c121d42f Helga Velroyen
  """Determine the volume group name.
1045 c121d42f Helga Velroyen

1046 c121d42f Helga Velroyen
  @type enabled_disk_templates: list of strings
1047 c121d42f Helga Velroyen
  @param enabled_disk_templates: cluster-wide enabled disk-templates
1048 c121d42f Helga Velroyen

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

1065 c121d42f Helga Velroyen
  """
1066 c121d42f Helga Velroyen
  drbd_helper = opts.drbd_helper
1067 31ccfc0e Helga Velroyen
  if enabled_disk_templates:
1068 31ccfc0e Helga Velroyen
    drbd_enabled = constants.DT_DRBD8 in enabled_disk_templates
1069 31ccfc0e Helga Velroyen
    if not drbd_enabled and opts.drbd_helper:
1070 38969795 Helga Velroyen
      ToStdout("You specified a DRBD usermode helper with "
1071 38969795 Helga Velroyen
               " --drbd-usermode-helper while DRBD is not enabled.")
1072 c121d42f Helga Velroyen
  return drbd_helper
1073 c121d42f Helga Velroyen
1074 c121d42f Helga Velroyen
1075 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
1076 90b6aa3a Manuel Franceschini
  """Modify the cluster.
1077 90b6aa3a Manuel Franceschini

1078 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1079 469ee405 Iustin Pop
  @type args: list
1080 469ee405 Iustin Pop
  @param args: should be an empty list
1081 469ee405 Iustin Pop
  @rtype: int
1082 469ee405 Iustin Pop
  @return: the desired exit code
1083 90b6aa3a Manuel Franceschini

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

1229 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1230 469ee405 Iustin Pop
  @type args: list
1231 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1232 469ee405 Iustin Pop
  @rtype: int
1233 469ee405 Iustin Pop
  @return: the desired exit code
1234 469ee405 Iustin Pop

1235 3ccafd0e Iustin Pop
  """
1236 3ccafd0e Iustin Pop
  command = args[0]
1237 3ccafd0e Iustin Pop
  client = GetClient()
1238 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
1239 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
1240 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
1241 3ccafd0e Iustin Pop
  elif command == "info":
1242 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
1243 3ccafd0e Iustin Pop
    if result[0]:
1244 3a24c527 Iustin Pop
      val = "set"
1245 3ccafd0e Iustin Pop
    else:
1246 3a24c527 Iustin Pop
      val = "unset"
1247 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
1248 2e668b38 Guido Trotter
  else:
1249 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1250 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1251 2e668b38 Guido Trotter
1252 3ccafd0e Iustin Pop
  return 0
1253 3ccafd0e Iustin Pop
1254 95b2e626 Michael Hanselmann
1255 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
1256 28b498cd Michael Hanselmann
  if until is None or until < time.time():
1257 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
1258 28b498cd Michael Hanselmann
  else:
1259 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
1260 28b498cd Michael Hanselmann
1261 28b498cd Michael Hanselmann
1262 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
1263 95b2e626 Michael Hanselmann
  """Watcher operations.
1264 95b2e626 Michael Hanselmann

1265 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1266 95b2e626 Michael Hanselmann
  @type args: list
1267 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1268 95b2e626 Michael Hanselmann
  @rtype: int
1269 95b2e626 Michael Hanselmann
  @return: the desired exit code
1270 95b2e626 Michael Hanselmann

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

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

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

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

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

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

1379 66d1f035 René Nussbaumer
  """
1380 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1381 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1382 66d1f035 René Nussbaumer
    """Init the object.
1383 66d1f035 René Nussbaumer

1384 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1385 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1386 66d1f035 René Nussbaumer
    @type node2ip: dict
1387 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1388 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1389 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1390 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1391 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1392 66d1f035 René Nussbaumer

1393 66d1f035 René Nussbaumer
    """
1394 66d1f035 René Nussbaumer
    self.down = set(node_list)
1395 66d1f035 René Nussbaumer
    self.up = set()
1396 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1397 66d1f035 René Nussbaumer
    self.success = True
1398 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1399 66d1f035 René Nussbaumer
    self.port = port
1400 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1401 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1402 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1403 66d1f035 René Nussbaumer
1404 66d1f035 René Nussbaumer
  def __call__(self):
1405 66d1f035 René Nussbaumer
    """When called we run action_cb.
1406 66d1f035 René Nussbaumer

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

1409 66d1f035 René Nussbaumer
    """
1410 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1411 66d1f035 René Nussbaumer
      self.success = False
1412 66d1f035 René Nussbaumer
1413 66d1f035 René Nussbaumer
    if self.down:
1414 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1415 66d1f035 René Nussbaumer
    else:
1416 66d1f035 René Nussbaumer
      return self.success
1417 66d1f035 René Nussbaumer
1418 66d1f035 René Nussbaumer
  def Wait(self, secs):
1419 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1420 66d1f035 René Nussbaumer

1421 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1422 66d1f035 René Nussbaumer

1423 66d1f035 René Nussbaumer
    """
1424 66d1f035 René Nussbaumer
    start = time.time()
1425 66d1f035 René Nussbaumer
    for node in self.down:
1426 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1427 66d1f035 René Nussbaumer
                       live_port_needed=True):
1428 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1429 66d1f035 René Nussbaumer
        self.up.add(node)
1430 66d1f035 René Nussbaumer
        self.down -= self.up
1431 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1432 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1433 66d1f035 René Nussbaumer
        return
1434 66d1f035 René Nussbaumer
1435 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1436 66d1f035 René Nussbaumer
1437 66d1f035 René Nussbaumer
1438 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1439 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1440 66d1f035 René Nussbaumer

1441 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1442 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1443 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1444 66d1f035 René Nussbaumer

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

1473 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1474 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1475 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1476 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1477 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1478 66d1f035 René Nussbaumer

1479 66d1f035 René Nussbaumer
  """
1480 66d1f035 René Nussbaumer
  start_inst_list = []
1481 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1482 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1483 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1484 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1485 66d1f035 René Nussbaumer
1486 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1487 66d1f035 René Nussbaumer
    del inst_map[inst]
1488 66d1f035 René Nussbaumer
1489 66d1f035 René Nussbaumer
  if start_inst_list:
1490 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1491 66d1f035 René Nussbaumer
1492 66d1f035 René Nussbaumer
  return True
1493 66d1f035 René Nussbaumer
1494 66d1f035 René Nussbaumer
1495 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1496 66d1f035 René Nussbaumer
  """Does the actual power on.
1497 66d1f035 René Nussbaumer

1498 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1499 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1500 66d1f035 René Nussbaumer
                         OOB)
1501 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1502 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1503 66d1f035 René Nussbaumer
  @return: The desired exit status
1504 66d1f035 René Nussbaumer

1505 66d1f035 René Nussbaumer
  """
1506 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1507 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1508 66d1f035 René Nussbaumer
             " manually if needed")
1509 66d1f035 René Nussbaumer
1510 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1511 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1512 66d1f035 René Nussbaumer
1513 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1514 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1515 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1516 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1517 66d1f035 René Nussbaumer
1518 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1519 66d1f035 René Nussbaumer
1520 66d1f035 René Nussbaumer
1521 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1522 66d1f035 René Nussbaumer
  """Does the actual power off.
1523 66d1f035 René Nussbaumer

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

1529 66d1f035 René Nussbaumer
  """
1530 3e0ed18c René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False, no_remember=True):
1531 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1532 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1533 66d1f035 René Nussbaumer
1534 66d1f035 René Nussbaumer
  if not node_list:
1535 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1536 66d1f035 René Nussbaumer
1537 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1538 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1539 66d1f035 René Nussbaumer
  else:
1540 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1541 66d1f035 René Nussbaumer
1542 66d1f035 René Nussbaumer
1543 fbde16f0 Helga Velroyen
def Epo(opts, args, qcl=None, _on_fn=_EpoOn, _off_fn=_EpoOff,
1544 1ca7b773 Michael Hanselmann
        _confirm_fn=ConfirmOperation,
1545 1ca7b773 Michael Hanselmann
        _stdout_fn=ToStdout, _stderr_fn=ToStderr):
1546 66d1f035 René Nussbaumer
  """EPO operations.
1547 66d1f035 René Nussbaumer

1548 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1549 66d1f035 René Nussbaumer
  @type args: list
1550 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1551 66d1f035 René Nussbaumer
  @rtype: int
1552 66d1f035 René Nussbaumer
  @return: the desired exit code
1553 66d1f035 René Nussbaumer

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

1628 ea9d3b40 Bernardo Dal Seno
  Currently it works only for ipolicy specs.
1629 ea9d3b40 Bernardo Dal Seno

1630 ea9d3b40 Bernardo Dal Seno
  """
1631 ea9d3b40 Bernardo Dal Seno
  cl = GetClient(query=True)
1632 ea9d3b40 Bernardo Dal Seno
  result = cl.QueryClusterInfo()
1633 ea9d3b40 Bernardo Dal Seno
  ToStdout(_GetCreateCommand(result))
1634 ea9d3b40 Bernardo Dal Seno
1635 ea9d3b40 Bernardo Dal Seno
1636 c51ffffe Klaus Aehlig
def _RunCommandAndReport(cmd):
1637 c51ffffe Klaus Aehlig
  """Run a command and report its output, iff it failed.
1638 c51ffffe Klaus Aehlig

1639 c51ffffe Klaus Aehlig
  @param cmd: the command to execute
1640 c51ffffe Klaus Aehlig
  @type cmd: list
1641 c51ffffe Klaus Aehlig
  @rtype: bool
1642 c51ffffe Klaus Aehlig
  @return: False, if the execution failed.
1643 c51ffffe Klaus Aehlig

1644 c51ffffe Klaus Aehlig
  """
1645 c51ffffe Klaus Aehlig
  result = utils.RunCmd(cmd)
1646 c51ffffe Klaus Aehlig
  if result.failed:
1647 c51ffffe Klaus Aehlig
    ToStderr("Command %s failed: %s; Output %s" %
1648 c51ffffe Klaus Aehlig
             (cmd, result.fail_reason, result.output))
1649 c51ffffe Klaus Aehlig
    return False
1650 c51ffffe Klaus Aehlig
  return True
1651 c51ffffe Klaus Aehlig
1652 c51ffffe Klaus Aehlig
1653 c51ffffe Klaus Aehlig
def _VerifyCommand(cmd):
1654 c51ffffe Klaus Aehlig
  """Verify that a given command succeeds on all online nodes.
1655 c51ffffe Klaus Aehlig

1656 c51ffffe Klaus Aehlig
  As this function is intended to run during upgrades, it
1657 c51ffffe Klaus Aehlig
  is implemented in such a way that it still works, if all Ganeti
1658 c51ffffe Klaus Aehlig
  daemons are down.
1659 c51ffffe Klaus Aehlig

1660 c51ffffe Klaus Aehlig
  @param cmd: the command to execute
1661 c51ffffe Klaus Aehlig
  @type cmd: list
1662 c51ffffe Klaus Aehlig
  @rtype: list
1663 c51ffffe Klaus Aehlig
  @return: the list of node names that are online where
1664 c51ffffe Klaus Aehlig
      the command failed.
1665 c51ffffe Klaus Aehlig

1666 c51ffffe Klaus Aehlig
  """
1667 c51ffffe Klaus Aehlig
  command = utils.text.ShellQuoteArgs([str(val) for val in cmd])
1668 c51ffffe Klaus Aehlig
1669 c51ffffe Klaus Aehlig
  nodes = ssconf.SimpleStore().GetOnlineNodeList()
1670 c51ffffe Klaus Aehlig
  master_node = ssconf.SimpleStore().GetMasterNode()
1671 c51ffffe Klaus Aehlig
  cluster_name = ssconf.SimpleStore().GetClusterName()
1672 c51ffffe Klaus Aehlig
1673 c51ffffe Klaus Aehlig
  # If master node is in 'nodes', make sure master node is at list end
1674 c51ffffe Klaus Aehlig
  if master_node in nodes:
1675 c51ffffe Klaus Aehlig
    nodes.remove(master_node)
1676 c51ffffe Klaus Aehlig
    nodes.append(master_node)
1677 c51ffffe Klaus Aehlig
1678 c51ffffe Klaus Aehlig
  failed = []
1679 c51ffffe Klaus Aehlig
1680 c51ffffe Klaus Aehlig
  srun = ssh.SshRunner(cluster_name=cluster_name)
1681 c51ffffe Klaus Aehlig
  for name in nodes:
1682 c51ffffe Klaus Aehlig
    result = srun.Run(name, constants.SSH_LOGIN_USER, command)
1683 c51ffffe Klaus Aehlig
    if result.exit_code != 0:
1684 c51ffffe Klaus Aehlig
      failed.append(name)
1685 c51ffffe Klaus Aehlig
1686 c51ffffe Klaus Aehlig
  return failed
1687 c51ffffe Klaus Aehlig
1688 c51ffffe Klaus Aehlig
1689 c51ffffe Klaus Aehlig
def _VerifyVersionInstalled(versionstring):
1690 c51ffffe Klaus Aehlig
  """Verify that the given version of ganeti is installed on all online nodes.
1691 c51ffffe Klaus Aehlig

1692 c51ffffe Klaus Aehlig
  Do nothing, if this is the case, otherwise print an appropriate
1693 c51ffffe Klaus Aehlig
  message to stderr.
1694 c51ffffe Klaus Aehlig

1695 c51ffffe Klaus Aehlig
  @param versionstring: the version to check for
1696 c51ffffe Klaus Aehlig
  @type versionstring: string
1697 c51ffffe Klaus Aehlig
  @rtype: bool
1698 c51ffffe Klaus Aehlig
  @return: True, if the version is installed on all online nodes
1699 c51ffffe Klaus Aehlig

1700 c51ffffe Klaus Aehlig
  """
1701 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand(["test", "-d",
1702 c51ffffe Klaus Aehlig
                             os.path.join(pathutils.PKGLIBDIR, versionstring)])
1703 c51ffffe Klaus Aehlig
  if badnodes:
1704 c51ffffe Klaus Aehlig
    ToStderr("Ganeti version %s not installed on nodes %s"
1705 c51ffffe Klaus Aehlig
             % (versionstring, ", ".join(badnodes)))
1706 c51ffffe Klaus Aehlig
    return False
1707 c51ffffe Klaus Aehlig
1708 c51ffffe Klaus Aehlig
  return True
1709 c51ffffe Klaus Aehlig
1710 c51ffffe Klaus Aehlig
1711 c51ffffe Klaus Aehlig
def _GetRunning():
1712 c51ffffe Klaus Aehlig
  """Determine the list of running jobs.
1713 c51ffffe Klaus Aehlig

1714 c51ffffe Klaus Aehlig
  @rtype: list
1715 c51ffffe Klaus Aehlig
  @return: the number of jobs still running
1716 c51ffffe Klaus Aehlig

1717 c51ffffe Klaus Aehlig
  """
1718 c51ffffe Klaus Aehlig
  cl = GetClient()
1719 c51ffffe Klaus Aehlig
  qfilter = qlang.MakeSimpleFilter("status",
1720 c51ffffe Klaus Aehlig
                                   frozenset([constants.JOB_STATUS_RUNNING]))
1721 c51ffffe Klaus Aehlig
  return len(cl.Query(constants.QR_JOB, [], qfilter).data)
1722 c51ffffe Klaus Aehlig
1723 c51ffffe Klaus Aehlig
1724 c51ffffe Klaus Aehlig
def _SetGanetiVersion(versionstring):
1725 c51ffffe Klaus Aehlig
  """Set the active version of ganeti to the given versionstring
1726 c51ffffe Klaus Aehlig

1727 c51ffffe Klaus Aehlig
  @type versionstring: string
1728 c51ffffe Klaus Aehlig
  @rtype: list
1729 c51ffffe Klaus Aehlig
  @return: the list of nodes where the version change failed
1730 c51ffffe Klaus Aehlig

1731 c51ffffe Klaus Aehlig
  """
1732 c51ffffe Klaus Aehlig
  failed = []
1733 645bba3a Klaus Aehlig
  if constants.HAS_GNU_LN:
1734 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1735 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", "-T",
1736 645bba3a Klaus Aehlig
         os.path.join(pathutils.PKGLIBDIR, versionstring),
1737 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/lib")]))
1738 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1739 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", "-T",
1740 645bba3a Klaus Aehlig
         os.path.join(pathutils.SHAREDIR, versionstring),
1741 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/share")]))
1742 645bba3a Klaus Aehlig
  else:
1743 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1744 645bba3a Klaus Aehlig
        ["rm", "-f", os.path.join(pathutils.SYSCONFDIR, "ganeti/lib")]))
1745 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1746 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", os.path.join(pathutils.PKGLIBDIR, versionstring),
1747 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/lib")]))
1748 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1749 645bba3a Klaus Aehlig
        ["rm", "-f", os.path.join(pathutils.SYSCONFDIR, "ganeti/share")]))
1750 645bba3a Klaus Aehlig
    failed.extend(_VerifyCommand(
1751 645bba3a Klaus Aehlig
        ["ln", "-s", "-f", os.path.join(pathutils.SHAREDIR, versionstring),
1752 645bba3a Klaus Aehlig
         os.path.join(pathutils.SYSCONFDIR, "ganeti/share")]))
1753 c51ffffe Klaus Aehlig
  return list(set(failed))
1754 c51ffffe Klaus Aehlig
1755 c51ffffe Klaus Aehlig
1756 c51ffffe Klaus Aehlig
def _ExecuteCommands(fns):
1757 c51ffffe Klaus Aehlig
  """Execute a list of functions, in reverse order.
1758 c51ffffe Klaus Aehlig

1759 c51ffffe Klaus Aehlig
  @type fns: list of functions.
1760 c51ffffe Klaus Aehlig
  @param fns: the functions to be executed.
1761 c51ffffe Klaus Aehlig

1762 c51ffffe Klaus Aehlig
  """
1763 c51ffffe Klaus Aehlig
  for fn in reversed(fns):
1764 c51ffffe Klaus Aehlig
    fn()
1765 c51ffffe Klaus Aehlig
1766 c51ffffe Klaus Aehlig
1767 16e81432 Klaus Aehlig
def _GetConfigVersion():
1768 16e81432 Klaus Aehlig
  """Determine the version the configuration file currently has.
1769 16e81432 Klaus Aehlig

1770 16e81432 Klaus Aehlig
  @rtype: tuple or None
1771 16e81432 Klaus Aehlig
  @return: (major, minor, revision) if the version can be determined,
1772 16e81432 Klaus Aehlig
      None otherwise
1773 16e81432 Klaus Aehlig

1774 16e81432 Klaus Aehlig
  """
1775 16e81432 Klaus Aehlig
  config_data = serializer.LoadJson(utils.ReadFile(pathutils.CLUSTER_CONF_FILE))
1776 16e81432 Klaus Aehlig
  try:
1777 16e81432 Klaus Aehlig
    config_version = config_data["version"]
1778 16e81432 Klaus Aehlig
  except KeyError:
1779 16e81432 Klaus Aehlig
    return None
1780 16e81432 Klaus Aehlig
  return utils.SplitVersion(config_version)
1781 16e81432 Klaus Aehlig
1782 16e81432 Klaus Aehlig
1783 36cfb584 Klaus Aehlig
def _ReadIntentToUpgrade():
1784 36cfb584 Klaus Aehlig
  """Read the file documenting the intent to upgrade the cluster.
1785 36cfb584 Klaus Aehlig

1786 36cfb584 Klaus Aehlig
  @rtype: string or None
1787 36cfb584 Klaus Aehlig
  @return: the version to upgrade to, if the file exists, and None
1788 36cfb584 Klaus Aehlig
      otherwise.
1789 36cfb584 Klaus Aehlig

1790 36cfb584 Klaus Aehlig
  """
1791 36cfb584 Klaus Aehlig
  if not os.path.isfile(pathutils.INTENT_TO_UPGRADE):
1792 36cfb584 Klaus Aehlig
    return None
1793 36cfb584 Klaus Aehlig
1794 36cfb584 Klaus Aehlig
  contentstring = utils.ReadFile(pathutils.INTENT_TO_UPGRADE)
1795 36cfb584 Klaus Aehlig
  contents = utils.UnescapeAndSplit(contentstring)
1796 36cfb584 Klaus Aehlig
  if len(contents) != 2:
1797 36cfb584 Klaus Aehlig
    # file syntactically mal-formed
1798 36cfb584 Klaus Aehlig
    return None
1799 36cfb584 Klaus Aehlig
  return contents[0]
1800 36cfb584 Klaus Aehlig
1801 36cfb584 Klaus Aehlig
1802 3b31c9da Klaus Aehlig
def _WriteIntentToUpgrade(version):
1803 3b31c9da Klaus Aehlig
  """Write file documenting the intent to upgrade the cluster.
1804 3b31c9da Klaus Aehlig

1805 3b31c9da Klaus Aehlig
  @type version: string
1806 3b31c9da Klaus Aehlig
  @param version: the version we intent to upgrade to
1807 3b31c9da Klaus Aehlig

1808 3b31c9da Klaus Aehlig
  """
1809 3b31c9da Klaus Aehlig
  utils.WriteFile(pathutils.INTENT_TO_UPGRADE,
1810 3b31c9da Klaus Aehlig
                  data=utils.EscapeAndJoin([version, "%d" % os.getpid()]))
1811 3b31c9da Klaus Aehlig
1812 3b31c9da Klaus Aehlig
1813 6c2a735a Klaus Aehlig
def _UpgradeBeforeConfigurationChange(versionstring):
1814 c51ffffe Klaus Aehlig
  """
1815 6c2a735a Klaus Aehlig
  Carry out all the tasks necessary for an upgrade that happen before
1816 6c2a735a Klaus Aehlig
  the configuration file, or Ganeti version, changes.
1817 c51ffffe Klaus Aehlig

1818 6c2a735a Klaus Aehlig
  @type versionstring: string
1819 6c2a735a Klaus Aehlig
  @param versionstring: the version to upgrade to
1820 6c2a735a Klaus Aehlig
  @rtype: (bool, list)
1821 6c2a735a Klaus Aehlig
  @return: tuple of a bool indicating success and a list of rollback tasks
1822 c51ffffe Klaus Aehlig

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

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

1880 c09c495c Klaus Aehlig
  @return: True upon success
1881 c09c495c Klaus Aehlig
  """
1882 c09c495c Klaus Aehlig
  ToStdout("Performing version-specific downgrade tasks.")
1883 c09c495c Klaus Aehlig
1884 52261ad2 Klaus Aehlig
  ToStdout("...removing client certificates ssconf file")
1885 52261ad2 Klaus Aehlig
  ssconffile = ssconf.SimpleStore().KeyToFilename(
1886 52261ad2 Klaus Aehlig
    constants.SS_MASTER_CANDIDATES_CERTS)
1887 52261ad2 Klaus Aehlig
  badnodes = _VerifyCommand(["rm", "-f", ssconffile])
1888 52261ad2 Klaus Aehlig
  if badnodes:
1889 52261ad2 Klaus Aehlig
    ToStderr("Warning: failed to clean up ssconf on %s."
1890 52261ad2 Klaus Aehlig
             % (", ".join(badnodes),))
1891 52261ad2 Klaus Aehlig
    return False
1892 52261ad2 Klaus Aehlig
1893 52261ad2 Klaus Aehlig
  ToStdout("...removing client certificates")
1894 52261ad2 Klaus Aehlig
  badnodes = _VerifyCommand(["rm", "-f", pathutils.NODED_CLIENT_CERT_FILE])
1895 52261ad2 Klaus Aehlig
  if badnodes:
1896 52261ad2 Klaus Aehlig
    ToStderr("Warning: failed to clean up certificates on %s."
1897 52261ad2 Klaus Aehlig
             % (", ".join(badnodes),))
1898 52261ad2 Klaus Aehlig
    return False
1899 52261ad2 Klaus Aehlig
1900 c09c495c Klaus Aehlig
  return True
1901 c09c495c Klaus Aehlig
1902 c09c495c Klaus Aehlig
1903 6c2a735a Klaus Aehlig
def _SwitchVersionAndConfig(versionstring, downgrade):
1904 6c2a735a Klaus Aehlig
  """
1905 6c2a735a Klaus Aehlig
  Switch to the new Ganeti version and change the configuration,
1906 6c2a735a Klaus Aehlig
  in correct order.
1907 6c2a735a Klaus Aehlig

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

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

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

1963 6c2a735a Klaus Aehlig
  @rtype: int
1964 6c2a735a Klaus Aehlig
  @return: the intended return value
1965 6c2a735a Klaus Aehlig

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

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

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