Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ ab0c6a39

History | View | Annotate | Download (69.3 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 912737ba Helga Velroyen
def _CheckNoLvmStorageOptDeprecated(opts):
82 912737ba Helga Velroyen
  """Checks if the legacy option '--no-lvm-storage' is used.
83 912737ba Helga Velroyen

84 912737ba Helga Velroyen
  """
85 912737ba Helga Velroyen
  if not opts.lvm_storage:
86 912737ba Helga Velroyen
    ToStderr("The option --no-lvm-storage is no longer supported. If you want"
87 912737ba Helga Velroyen
             " to disable lvm-based storage cluster-wide, use the option"
88 912737ba Helga Velroyen
             " --enabled-disk-templates to disable all of these lvm-base disk "
89 912737ba Helga Velroyen
             "  templates: %s" %
90 d48c944b Helga Velroyen
             utils.CommaJoin(constants.DTS_LVM))
91 912737ba Helga Velroyen
    return 1
92 912737ba Helga Velroyen
93 912737ba Helga Velroyen
94 c121d42f Helga Velroyen
def _InitEnabledDiskTemplates(opts):
95 c121d42f Helga Velroyen
  """Initialize the list of enabled disk templates.
96 c121d42f Helga Velroyen

97 c121d42f Helga Velroyen
  """
98 c121d42f Helga Velroyen
  if opts.enabled_disk_templates:
99 c121d42f Helga Velroyen
    return opts.enabled_disk_templates.split(",")
100 c121d42f Helga Velroyen
  else:
101 c121d42f Helga Velroyen
    return constants.DEFAULT_ENABLED_DISK_TEMPLATES
102 c121d42f Helga Velroyen
103 c121d42f Helga Velroyen
104 c121d42f Helga Velroyen
def _InitVgName(opts, enabled_disk_templates):
105 c121d42f Helga Velroyen
  """Initialize the volume group name.
106 c121d42f Helga Velroyen

107 c121d42f Helga Velroyen
  @type enabled_disk_templates: list of strings
108 c121d42f Helga Velroyen
  @param enabled_disk_templates: cluster-wide enabled disk templates
109 c121d42f Helga Velroyen

110 c121d42f Helga Velroyen
  """
111 c121d42f Helga Velroyen
  vg_name = None
112 c121d42f Helga Velroyen
  if opts.vg_name is not None:
113 c121d42f Helga Velroyen
    vg_name = opts.vg_name
114 c121d42f Helga Velroyen
    if vg_name:
115 c121d42f Helga Velroyen
      if not utils.IsLvmEnabled(enabled_disk_templates):
116 c121d42f Helga Velroyen
        ToStdout("You specified a volume group with --vg-name, but you did not"
117 c121d42f Helga Velroyen
                 " enable any disk template that uses lvm.")
118 c121d42f Helga Velroyen
    elif utils.IsLvmEnabled(enabled_disk_templates):
119 c121d42f Helga Velroyen
      raise errors.OpPrereqError(
120 c121d42f Helga Velroyen
          "LVM disk templates are enabled, but vg name not set.")
121 c121d42f Helga Velroyen
  elif utils.IsLvmEnabled(enabled_disk_templates):
122 c121d42f Helga Velroyen
    vg_name = constants.DEFAULT_VG
123 c121d42f Helga Velroyen
  return vg_name
124 c121d42f Helga Velroyen
125 c121d42f Helga Velroyen
126 7796e1f8 Helga Velroyen
def _InitDrbdHelper(opts, enabled_disk_templates):
127 c121d42f Helga Velroyen
  """Initialize the DRBD usermode helper.
128 c121d42f Helga Velroyen

129 c121d42f Helga Velroyen
  """
130 7796e1f8 Helga Velroyen
  drbd_enabled = constants.DT_DRBD8 in enabled_disk_templates
131 7796e1f8 Helga Velroyen
132 38969795 Helga Velroyen
  if not drbd_enabled and opts.drbd_helper is not None:
133 38969795 Helga Velroyen
    ToStdout("Note: You specified a DRBD usermode helper, while DRBD storage"
134 38969795 Helga Velroyen
             " is not enabled.")
135 c121d42f Helga Velroyen
136 7796e1f8 Helga Velroyen
  if drbd_enabled:
137 7796e1f8 Helga Velroyen
    if opts.drbd_helper is None:
138 7796e1f8 Helga Velroyen
      return constants.DEFAULT_DRBD_HELPER
139 7796e1f8 Helga Velroyen
    if opts.drbd_helper == '':
140 7796e1f8 Helga Velroyen
      raise errors.OpPrereqError(
141 7796e1f8 Helga Velroyen
          "Unsetting the drbd usermode helper while enabling DRBD is not"
142 7796e1f8 Helga Velroyen
          " allowed.")
143 c121d42f Helga Velroyen
144 c121d42f Helga Velroyen
  return opts.drbd_helper
145 c121d42f Helga Velroyen
146 c121d42f Helga Velroyen
147 4331f6cd Michael Hanselmann
@UsesRPC
148 a8083063 Iustin Pop
def InitCluster(opts, args):
149 a8083063 Iustin Pop
  """Initialize the cluster.
150 a8083063 Iustin Pop

151 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
152 469ee405 Iustin Pop
  @type args: list
153 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
154 469ee405 Iustin Pop
      cluster name
155 469ee405 Iustin Pop
  @rtype: int
156 469ee405 Iustin Pop
  @return: the desired exit code
157 a8083063 Iustin Pop

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

321 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
322 469ee405 Iustin Pop
  @type args: list
323 469ee405 Iustin Pop
  @param args: should be an empty list
324 469ee405 Iustin Pop
  @rtype: int
325 469ee405 Iustin Pop
  @return: the desired exit code
326 098c0958 Michael Hanselmann

327 a8083063 Iustin Pop
  """
328 a8083063 Iustin Pop
  if not opts.yes_do_it:
329 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
330 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
331 a8083063 Iustin Pop
    return 1
332 a8083063 Iustin Pop
333 c6d43e9e Iustin Pop
  op = opcodes.OpClusterDestroy()
334 1c3231aa Thomas Thrainer
  master_uuid = SubmitOpCode(op, opts=opts)
335 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
336 140aa4a8 Iustin Pop
  # shutdown all the daemons
337 1c3231aa Thomas Thrainer
  bootstrap.FinalizeClusterDestroy(master_uuid)
338 a8083063 Iustin Pop
  return 0
339 a8083063 Iustin Pop
340 a8083063 Iustin Pop
341 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
342 07bd8a51 Iustin Pop
  """Rename the cluster.
343 07bd8a51 Iustin Pop

344 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
345 469ee405 Iustin Pop
  @type args: list
346 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
347 469ee405 Iustin Pop
  @rtype: int
348 469ee405 Iustin Pop
  @return: the desired exit code
349 07bd8a51 Iustin Pop

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

377 fb926117 Andrea Spadaccini
  """
378 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
379 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
380 fb926117 Andrea Spadaccini
  return 0
381 fb926117 Andrea Spadaccini
382 fb926117 Andrea Spadaccini
383 fb926117 Andrea Spadaccini
def DeactivateMasterIp(opts, args):
384 fb926117 Andrea Spadaccini
  """Deactivates the master IP.
385 fb926117 Andrea Spadaccini

386 fb926117 Andrea Spadaccini
  """
387 fb926117 Andrea Spadaccini
  if not opts.confirm:
388 fb926117 Andrea Spadaccini
    usertext = ("This will disable the master IP. All the open connections to"
389 fb926117 Andrea Spadaccini
                " the master IP will be closed. To reach the master you will"
390 fb926117 Andrea Spadaccini
                " need to use its node IP."
391 fb926117 Andrea Spadaccini
                " Continue?")
392 fb926117 Andrea Spadaccini
    if not AskUser(usertext):
393 fb926117 Andrea Spadaccini
      return 1
394 fb926117 Andrea Spadaccini
395 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterDeactivateMasterIp()
396 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
397 fb926117 Andrea Spadaccini
  return 0
398 fb926117 Andrea Spadaccini
399 fb926117 Andrea Spadaccini
400 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
401 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
402 afee0879 Iustin Pop

403 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
404 afee0879 Iustin Pop
  @type args: list
405 afee0879 Iustin Pop
  @param args: empty list
406 afee0879 Iustin Pop
  @rtype: int
407 afee0879 Iustin Pop
  @return: the desired exit code
408 afee0879 Iustin Pop

409 afee0879 Iustin Pop
  """
410 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
411 0c455e40 Klaus Aehlig
  if opts.yes_do_it:
412 0c455e40 Klaus Aehlig
    SubmitOpCodeToDrainedQueue(op)
413 0c455e40 Klaus Aehlig
  else:
414 0c455e40 Klaus Aehlig
    SubmitOrSend(op, opts)
415 afee0879 Iustin Pop
  return 0
416 afee0879 Iustin Pop
417 afee0879 Iustin Pop
418 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
419 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
420 a8083063 Iustin Pop

421 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
422 469ee405 Iustin Pop
  @type args: list
423 469ee405 Iustin Pop
  @param args: should be an empty list
424 469ee405 Iustin Pop
  @rtype: int
425 469ee405 Iustin Pop
  @return: the desired exit code
426 a8083063 Iustin Pop

427 a8083063 Iustin Pop
  """
428 42ab9ac4 Iustin Pop
  cl = GetClient(query=True)
429 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
430 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
431 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
432 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
433 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
434 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
435 026f444f Thomas Thrainer
  ToStdout("VCS version: %s", result["vcs_version"])
436 a8083063 Iustin Pop
  return 0
437 a8083063 Iustin Pop
438 a8083063 Iustin Pop
439 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
440 a8083063 Iustin Pop
  """Write name of master node to the standard output.
441 a8083063 Iustin Pop

442 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
443 469ee405 Iustin Pop
  @type args: list
444 469ee405 Iustin Pop
  @param args: should be an empty list
445 469ee405 Iustin Pop
  @rtype: int
446 469ee405 Iustin Pop
  @return: the desired exit code
447 a8083063 Iustin Pop

448 a8083063 Iustin Pop
  """
449 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
450 8eb148ae Iustin Pop
  ToStdout(master)
451 a8083063 Iustin Pop
  return 0
452 a8083063 Iustin Pop
453 cac599f1 Michael Hanselmann
454 0e79564a Bernardo Dal Seno
def _FormatGroupedParams(paramsdict, roman=False):
455 0e79564a Bernardo Dal Seno
  """Format Grouped parameters (be, nic, disk) by group.
456 1094acda Guido Trotter

457 1094acda Guido Trotter
  @type paramsdict: dict of dicts
458 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
459 0e79564a Bernardo Dal Seno
  @rtype: dict of dicts
460 0e79564a Bernardo Dal Seno
  @return: copy of the input dictionaries with strings as values
461 1094acda Guido Trotter

462 1094acda Guido Trotter
  """
463 0e79564a Bernardo Dal Seno
  ret = {}
464 0e79564a Bernardo Dal Seno
  for (item, val) in paramsdict.items():
465 664a9d73 René Nussbaumer
    if isinstance(val, dict):
466 0e79564a Bernardo Dal Seno
      ret[item] = _FormatGroupedParams(val, roman=roman)
467 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
468 0e79564a Bernardo Dal Seno
      ret[item] = compat.TryToRoman(val)
469 664a9d73 René Nussbaumer
    else:
470 0e79564a Bernardo Dal Seno
      ret[item] = str(val)
471 0e79564a Bernardo Dal Seno
  return ret
472 a8083063 Iustin Pop
473 cac599f1 Michael Hanselmann
474 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
475 a8083063 Iustin Pop
  """Shows cluster information.
476 a8083063 Iustin Pop

477 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
478 469ee405 Iustin Pop
  @type args: list
479 469ee405 Iustin Pop
  @param args: should be an empty list
480 469ee405 Iustin Pop
  @rtype: int
481 469ee405 Iustin Pop
  @return: the desired exit code
482 469ee405 Iustin Pop

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

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

582 a8083063 Iustin Pop
  """
583 b3989551 Iustin Pop
  filename = args[0]
584 74a4fc94 Klaus Aehlig
  filename = os.path.abspath(filename)
585 74a4fc94 Klaus Aehlig
586 b3989551 Iustin Pop
  if not os.path.exists(filename):
587 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
588 debac808 Iustin Pop
                               errors.ECODE_INVAL)
589 b3989551 Iustin Pop
590 56bece1f Iustin Pop
  cl = GetClient()
591 56bece1f Iustin Pop
592 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
593 56bece1f Iustin Pop
594 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
595 b6e88032 Michael Hanselmann
                           secondary_ips=opts.use_replication_network,
596 b6e88032 Michael Hanselmann
                           nodegroup=opts.nodegroup)
597 e00ea635 Michael Hanselmann
598 224ff0f7 Michael Hanselmann
  srun = ssh.SshRunner(cluster_name)
599 b3989551 Iustin Pop
  for node in results:
600 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
601 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
602 b3989551 Iustin Pop
603 a8083063 Iustin Pop
  return 0
604 a8083063 Iustin Pop
605 a8083063 Iustin Pop
606 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
607 a8083063 Iustin Pop
  """Run a command on some nodes.
608 a8083063 Iustin Pop

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1031 c121d42f Helga Velroyen
  """
1032 c121d42f Helga Velroyen
  if opts.enabled_disk_templates:
1033 c121d42f Helga Velroyen
    return opts.enabled_disk_templates.split(",")
1034 c121d42f Helga Velroyen
  else:
1035 c121d42f Helga Velroyen
    return None
1036 c121d42f Helga Velroyen
1037 c121d42f Helga Velroyen
1038 c121d42f Helga Velroyen
def _GetVgName(opts, enabled_disk_templates):
1039 c121d42f Helga Velroyen
  """Determine the volume group name.
1040 c121d42f Helga Velroyen

1041 c121d42f Helga Velroyen
  @type enabled_disk_templates: list of strings
1042 c121d42f Helga Velroyen
  @param enabled_disk_templates: cluster-wide enabled disk-templates
1043 c121d42f Helga Velroyen

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

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

1073 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1074 469ee405 Iustin Pop
  @type args: list
1075 469ee405 Iustin Pop
  @param args: should be an empty list
1076 469ee405 Iustin Pop
  @rtype: int
1077 469ee405 Iustin Pop
  @return: the desired exit code
1078 90b6aa3a Manuel Franceschini

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1419 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1420 66d1f035 René Nussbaumer

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

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

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

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

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

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

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

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

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

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

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

1625 ea9d3b40 Bernardo Dal Seno
  Currently it works only for ipolicy specs.
1626 ea9d3b40 Bernardo Dal Seno

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

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

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

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

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

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

1689 c51ffffe Klaus Aehlig
  Do nothing, if this is the case, otherwise print an appropriate
1690 c51ffffe Klaus Aehlig
  message to stderr.
1691 c51ffffe Klaus Aehlig

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

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

1711 c51ffffe Klaus Aehlig
  @rtype: list
1712 c51ffffe Klaus Aehlig
  @return: the number of jobs still running
1713 c51ffffe Klaus Aehlig

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

1724 c51ffffe Klaus Aehlig
  @type versionstring: string
1725 c51ffffe Klaus Aehlig
  @rtype: list
1726 c51ffffe Klaus Aehlig
  @return: the list of nodes where the version change failed
1727 c51ffffe Klaus Aehlig

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

1756 c51ffffe Klaus Aehlig
  @type fns: list of functions.
1757 c51ffffe Klaus Aehlig
  @param fns: the functions to be executed.
1758 c51ffffe Klaus Aehlig

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

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

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

1783 4a67e386 Klaus Aehlig
  @rtype: (string, string) or (None, None)
1784 4a67e386 Klaus Aehlig
  @return: (old version, version to upgrade to), if the file exists,
1785 4a67e386 Klaus Aehlig
      and (None, None) otherwise.
1786 36cfb584 Klaus Aehlig

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

1802 3b31c9da Klaus Aehlig
  @type version: string
1803 3b31c9da Klaus Aehlig
  @param version: the version we intent to upgrade to
1804 3b31c9da Klaus Aehlig

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

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

1821 6c2a735a Klaus Aehlig
  """
1822 c51ffffe Klaus Aehlig
  rollback = []
1823 c51ffffe Klaus Aehlig
1824 c51ffffe Klaus Aehlig
  if not _VerifyVersionInstalled(versionstring):
1825 6c2a735a Klaus Aehlig
    return (False, rollback)
1826 c51ffffe Klaus Aehlig
1827 3b31c9da Klaus Aehlig
  _WriteIntentToUpgrade(versionstring)
1828 3b31c9da Klaus Aehlig
  rollback.append(
1829 3b31c9da Klaus Aehlig
    lambda: utils.RunCmd(["rm", "-f", pathutils.INTENT_TO_UPGRADE]))
1830 c51ffffe Klaus Aehlig
1831 c51ffffe Klaus Aehlig
  ToStdout("Draining queue")
1832 c51ffffe Klaus Aehlig
  client = GetClient()
1833 c51ffffe Klaus Aehlig
  client.SetQueueDrainFlag(True)
1834 c51ffffe Klaus Aehlig
1835 c51ffffe Klaus Aehlig
  rollback.append(lambda: GetClient().SetQueueDrainFlag(False))
1836 c51ffffe Klaus Aehlig
1837 c51ffffe Klaus Aehlig
  if utils.SimpleRetry(0, _GetRunning,
1838 c51ffffe Klaus Aehlig
                       constants.UPGRADE_QUEUE_POLL_INTERVAL,
1839 c51ffffe Klaus Aehlig
                       constants.UPGRADE_QUEUE_DRAIN_TIMEOUT):
1840 c51ffffe Klaus Aehlig
    ToStderr("Failed to completely empty the queue.")
1841 6c2a735a Klaus Aehlig
    return (False, rollback)
1842 c51ffffe Klaus Aehlig
1843 c51ffffe Klaus Aehlig
  ToStdout("Stopping daemons on master node.")
1844 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport([pathutils.DAEMON_UTIL, "stop-all"]):
1845 6c2a735a Klaus Aehlig
    return (False, rollback)
1846 c51ffffe Klaus Aehlig
1847 c51ffffe Klaus Aehlig
  if not _VerifyVersionInstalled(versionstring):
1848 c51ffffe Klaus Aehlig
    utils.RunCmd([pathutils.DAEMON_UTIL, "start-all"])
1849 6c2a735a Klaus Aehlig
    return (False, rollback)
1850 c51ffffe Klaus Aehlig
1851 c51ffffe Klaus Aehlig
  ToStdout("Stopping daemons everywhere.")
1852 c51ffffe Klaus Aehlig
  rollback.append(lambda: _VerifyCommand([pathutils.DAEMON_UTIL, "start-all"]))
1853 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "stop-all"])
1854 c51ffffe Klaus Aehlig
  if badnodes:
1855 c51ffffe Klaus Aehlig
    ToStderr("Failed to stop daemons on %s." % (", ".join(badnodes),))
1856 6c2a735a Klaus Aehlig
    return (False, rollback)
1857 c51ffffe Klaus Aehlig
1858 c51ffffe Klaus Aehlig
  backuptar = os.path.join(pathutils.LOCALSTATEDIR,
1859 c51ffffe Klaus Aehlig
                           "lib/ganeti%d.tar" % time.time())
1860 c51ffffe Klaus Aehlig
  ToStdout("Backing up configuration as %s" % backuptar)
1861 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["tar", "cf", backuptar,
1862 c51ffffe Klaus Aehlig
                               pathutils.DATA_DIR]):
1863 6c2a735a Klaus Aehlig
    return (False, rollback)
1864 6c2a735a Klaus Aehlig
1865 6c2a735a Klaus Aehlig
  return (True, rollback)
1866 c51ffffe Klaus Aehlig
1867 6c2a735a Klaus Aehlig
1868 6c2a735a Klaus Aehlig
def _SwitchVersionAndConfig(versionstring, downgrade):
1869 6c2a735a Klaus Aehlig
  """
1870 6c2a735a Klaus Aehlig
  Switch to the new Ganeti version and change the configuration,
1871 6c2a735a Klaus Aehlig
  in correct order.
1872 6c2a735a Klaus Aehlig

1873 6c2a735a Klaus Aehlig
  @type versionstring: string
1874 6c2a735a Klaus Aehlig
  @param versionstring: the version to change to
1875 6c2a735a Klaus Aehlig
  @type downgrade: bool
1876 6c2a735a Klaus Aehlig
  @param downgrade: True, if the configuration should be downgraded
1877 6c2a735a Klaus Aehlig
  @rtype: (bool, list)
1878 6c2a735a Klaus Aehlig
  @return: tupe of a bool indicating success, and a list of
1879 6c2a735a Klaus Aehlig
      additional rollback tasks
1880 6c2a735a Klaus Aehlig

1881 6c2a735a Klaus Aehlig
  """
1882 6c2a735a Klaus Aehlig
  rollback = []
1883 c51ffffe Klaus Aehlig
  if downgrade:
1884 c51ffffe Klaus Aehlig
    ToStdout("Downgrading configuration")
1885 c51ffffe Klaus Aehlig
    if not _RunCommandAndReport([pathutils.CFGUPGRADE, "--downgrade", "-f"]):
1886 6c2a735a Klaus Aehlig
      return (False, rollback)
1887 c51ffffe Klaus Aehlig
1888 c51ffffe Klaus Aehlig
  # Configuration change is the point of no return. From then onwards, it is
1889 c51ffffe Klaus Aehlig
  # safer to push through the up/dowgrade than to try to roll it back.
1890 c51ffffe Klaus Aehlig
1891 c51ffffe Klaus Aehlig
  ToStdout("Switching to version %s on all nodes" % versionstring)
1892 c51ffffe Klaus Aehlig
  rollback.append(lambda: _SetGanetiVersion(constants.DIR_VERSION))
1893 c51ffffe Klaus Aehlig
  badnodes = _SetGanetiVersion(versionstring)
1894 c51ffffe Klaus Aehlig
  if badnodes:
1895 c51ffffe Klaus Aehlig
    ToStderr("Failed to switch to Ganeti version %s on nodes %s"
1896 c51ffffe Klaus Aehlig
             % (versionstring, ", ".join(badnodes)))
1897 c51ffffe Klaus Aehlig
    if not downgrade:
1898 6c2a735a Klaus Aehlig
      return (False, rollback)
1899 c51ffffe Klaus Aehlig
1900 c51ffffe Klaus Aehlig
  # Now that we have changed to the new version of Ganeti we should
1901 c51ffffe Klaus Aehlig
  # not communicate over luxi any more, as luxi might have changed in
1902 c51ffffe Klaus Aehlig
  # incompatible ways. Therefore, manually call the corresponding ganeti
1903 c51ffffe Klaus Aehlig
  # commands using their canonical (version independent) path.
1904 c51ffffe Klaus Aehlig
1905 c51ffffe Klaus Aehlig
  if not downgrade:
1906 c51ffffe Klaus Aehlig
    ToStdout("Upgrading configuration")
1907 c51ffffe Klaus Aehlig
    if not _RunCommandAndReport([pathutils.CFGUPGRADE, "-f"]):
1908 6c2a735a Klaus Aehlig
      return (False, rollback)
1909 6c2a735a Klaus Aehlig
1910 6c2a735a Klaus Aehlig
  return (True, rollback)
1911 6c2a735a Klaus Aehlig
1912 6c2a735a Klaus Aehlig
1913 4a67e386 Klaus Aehlig
def _UpgradeAfterConfigurationChange(oldversion):
1914 6c2a735a Klaus Aehlig
  """
1915 6c2a735a Klaus Aehlig
  Carry out the upgrade actions necessary after switching to the new
1916 6c2a735a Klaus Aehlig
  Ganeti version and updating the configuration.
1917 6c2a735a Klaus Aehlig

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

1923 4a67e386 Klaus Aehlig
  @param oldversion: the version the upgrade started from
1924 4a67e386 Klaus Aehlig
  @type oldversion: string
1925 6c2a735a Klaus Aehlig
  @rtype: int
1926 6c2a735a Klaus Aehlig
  @return: the intended return value
1927 6c2a735a Klaus Aehlig

1928 6c2a735a Klaus Aehlig
  """
1929 6c2a735a Klaus Aehlig
  returnvalue = 0
1930 c51ffffe Klaus Aehlig
1931 c51ffffe Klaus Aehlig
  ToStdout("Ensuring directories everywhere.")
1932 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.ENSURE_DIRS])
1933 c51ffffe Klaus Aehlig
  if badnodes:
1934 c51ffffe Klaus Aehlig
    ToStderr("Warning: failed to ensure directories on %s." %
1935 c51ffffe Klaus Aehlig
             (", ".join(badnodes)))
1936 c51ffffe Klaus Aehlig
    returnvalue = 1
1937 c51ffffe Klaus Aehlig
1938 401b773e Klaus Aehlig
  ToStdout("Starting daemons everywhere.")
1939 401b773e Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "start-all"])
1940 401b773e Klaus Aehlig
  if badnodes:
1941 401b773e Klaus Aehlig
    ToStderr("Warning: failed to start daemons on %s." % (", ".join(badnodes),))
1942 401b773e Klaus Aehlig
    returnvalue = 1
1943 401b773e Klaus Aehlig
1944 c51ffffe Klaus Aehlig
  ToStdout("Redistributing the configuration.")
1945 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "redist-conf", "--yes-do-it"]):
1946 c51ffffe Klaus Aehlig
    returnvalue = 1
1947 c51ffffe Klaus Aehlig
1948 c51ffffe Klaus Aehlig
  ToStdout("Restarting daemons everywhere.")
1949 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "stop-all"])
1950 c51ffffe Klaus Aehlig
  badnodes.extend(_VerifyCommand([pathutils.DAEMON_UTIL, "start-all"]))
1951 c51ffffe Klaus Aehlig
  if badnodes:
1952 c51ffffe Klaus Aehlig
    ToStderr("Warning: failed to start daemons on %s." %
1953 c51ffffe Klaus Aehlig
             (", ".join(list(set(badnodes))),))
1954 c51ffffe Klaus Aehlig
    returnvalue = 1
1955 c51ffffe Klaus Aehlig
1956 c51ffffe Klaus Aehlig
  ToStdout("Undraining the queue.")
1957 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "queue", "undrain"]):
1958 c51ffffe Klaus Aehlig
    returnvalue = 1
1959 c51ffffe Klaus Aehlig
1960 3b31c9da Klaus Aehlig
  _RunCommandAndReport(["rm", "-f", pathutils.INTENT_TO_UPGRADE])
1961 c51ffffe Klaus Aehlig
1962 4a67e386 Klaus Aehlig
  ToStdout("Running post-upgrade hooks")
1963 4a67e386 Klaus Aehlig
  if not _RunCommandAndReport([pathutils.POST_UPGRADE, oldversion]):
1964 4a67e386 Klaus Aehlig
    returnvalue = 1
1965 4a67e386 Klaus Aehlig
1966 c51ffffe Klaus Aehlig
  ToStdout("Verifying cluster.")
1967 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "verify"]):
1968 c51ffffe Klaus Aehlig
    returnvalue = 1
1969 c51ffffe Klaus Aehlig
1970 c51ffffe Klaus Aehlig
  return returnvalue
1971 c51ffffe Klaus Aehlig
1972 c51ffffe Klaus Aehlig
1973 6c2a735a Klaus Aehlig
def UpgradeGanetiCommand(opts, args):
1974 6c2a735a Klaus Aehlig
  """Upgrade a cluster to a new ganeti version.
1975 6c2a735a Klaus Aehlig

1976 6c2a735a Klaus Aehlig
  @param opts: the command line options selected by the user
1977 6c2a735a Klaus Aehlig
  @type args: list
1978 6c2a735a Klaus Aehlig
  @param args: should be an empty list
1979 6c2a735a Klaus Aehlig
  @rtype: int
1980 6c2a735a Klaus Aehlig
  @return: the desired exit code
1981 6c2a735a Klaus Aehlig

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