Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 3cac836b

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1415 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1416 66d1f035 René Nussbaumer

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

1435 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1436 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1437 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1438 66d1f035 René Nussbaumer

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

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

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

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

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

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

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

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

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

1621 ea9d3b40 Bernardo Dal Seno
  Currently it works only for ipolicy specs.
1622 ea9d3b40 Bernardo Dal Seno

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

1632 c51ffffe Klaus Aehlig
  @param cmd: the command to execute
1633 c51ffffe Klaus Aehlig
  @type cmd: list
1634 c51ffffe Klaus Aehlig
  @rtype: bool
1635 c51ffffe Klaus Aehlig
  @return: False, if the execution failed.
1636 c51ffffe Klaus Aehlig

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

1649 c51ffffe Klaus Aehlig
  As this function is intended to run during upgrades, it
1650 c51ffffe Klaus Aehlig
  is implemented in such a way that it still works, if all Ganeti
1651 c51ffffe Klaus Aehlig
  daemons are down.
1652 c51ffffe Klaus Aehlig

1653 c51ffffe Klaus Aehlig
  @param cmd: the command to execute
1654 c51ffffe Klaus Aehlig
  @type cmd: list
1655 c51ffffe Klaus Aehlig
  @rtype: list
1656 c51ffffe Klaus Aehlig
  @return: the list of node names that are online where
1657 c51ffffe Klaus Aehlig
      the command failed.
1658 c51ffffe Klaus Aehlig

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

1685 c51ffffe Klaus Aehlig
  Do nothing, if this is the case, otherwise print an appropriate
1686 c51ffffe Klaus Aehlig
  message to stderr.
1687 c51ffffe Klaus Aehlig

1688 c51ffffe Klaus Aehlig
  @param versionstring: the version to check for
1689 c51ffffe Klaus Aehlig
  @type versionstring: string
1690 c51ffffe Klaus Aehlig
  @rtype: bool
1691 c51ffffe Klaus Aehlig
  @return: True, if the version is installed on all online nodes
1692 c51ffffe Klaus Aehlig

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

1707 c51ffffe Klaus Aehlig
  @rtype: list
1708 c51ffffe Klaus Aehlig
  @return: the number of jobs still running
1709 c51ffffe Klaus Aehlig

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

1720 c51ffffe Klaus Aehlig
  @type versionstring: string
1721 c51ffffe Klaus Aehlig
  @rtype: list
1722 c51ffffe Klaus Aehlig
  @return: the list of nodes where the version change failed
1723 c51ffffe Klaus Aehlig

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

1752 c51ffffe Klaus Aehlig
  @type fns: list of functions.
1753 c51ffffe Klaus Aehlig
  @param fns: the functions to be executed.
1754 c51ffffe Klaus Aehlig

1755 c51ffffe Klaus Aehlig
  """
1756 c51ffffe Klaus Aehlig
  for fn in reversed(fns):
1757 c51ffffe Klaus Aehlig
    fn()
1758 c51ffffe Klaus Aehlig
1759 c51ffffe Klaus Aehlig
1760 16e81432 Klaus Aehlig
def _GetConfigVersion():
1761 16e81432 Klaus Aehlig
  """Determine the version the configuration file currently has.
1762 16e81432 Klaus Aehlig

1763 16e81432 Klaus Aehlig
  @rtype: tuple or None
1764 16e81432 Klaus Aehlig
  @return: (major, minor, revision) if the version can be determined,
1765 16e81432 Klaus Aehlig
      None otherwise
1766 16e81432 Klaus Aehlig

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

1779 36cfb584 Klaus Aehlig
  @rtype: string or None
1780 36cfb584 Klaus Aehlig
  @return: the version to upgrade to, if the file exists, and None
1781 36cfb584 Klaus Aehlig
      otherwise.
1782 36cfb584 Klaus Aehlig

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

1798 3b31c9da Klaus Aehlig
  @type version: string
1799 3b31c9da Klaus Aehlig
  @param version: the version we intent to upgrade to
1800 3b31c9da Klaus Aehlig

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

1812 6c2a735a Klaus Aehlig
  @type versionstring: string
1813 6c2a735a Klaus Aehlig
  @param versionstring: the version to upgrade to
1814 6c2a735a Klaus Aehlig
  @rtype: (bool, list)
1815 6c2a735a Klaus Aehlig
  @return: tuple of a bool indicating success and a list of rollback tasks
1816 c51ffffe Klaus Aehlig

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

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

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

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

1919 6c2a735a Klaus Aehlig
  @rtype: int
1920 6c2a735a Klaus Aehlig
  @return: the intended return value
1921 6c2a735a Klaus Aehlig

1922 6c2a735a Klaus Aehlig
  """
1923 6c2a735a Klaus Aehlig
  returnvalue = 0
1924 c51ffffe Klaus Aehlig
1925 c51ffffe Klaus Aehlig
  ToStdout("Starting daemons everywhere.")
1926 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "start-all"])
1927 c51ffffe Klaus Aehlig
  if badnodes:
1928 c51ffffe Klaus Aehlig
    ToStderr("Warning: failed to start daemons on %s." % (", ".join(badnodes),))
1929 c51ffffe Klaus Aehlig
    returnvalue = 1
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 c51ffffe Klaus Aehlig
  ToStdout("Redistributing the configuration.")
1939 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "redist-conf", "--yes-do-it"]):
1940 c51ffffe Klaus Aehlig
    returnvalue = 1
1941 c51ffffe Klaus Aehlig
1942 c51ffffe Klaus Aehlig
  ToStdout("Restarting daemons everywhere.")
1943 c51ffffe Klaus Aehlig
  badnodes = _VerifyCommand([pathutils.DAEMON_UTIL, "stop-all"])
1944 c51ffffe Klaus Aehlig
  badnodes.extend(_VerifyCommand([pathutils.DAEMON_UTIL, "start-all"]))
1945 c51ffffe Klaus Aehlig
  if badnodes:
1946 c51ffffe Klaus Aehlig
    ToStderr("Warning: failed to start daemons on %s." %
1947 c51ffffe Klaus Aehlig
             (", ".join(list(set(badnodes))),))
1948 c51ffffe Klaus Aehlig
    returnvalue = 1
1949 c51ffffe Klaus Aehlig
1950 c51ffffe Klaus Aehlig
  ToStdout("Undraining the queue.")
1951 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "queue", "undrain"]):
1952 c51ffffe Klaus Aehlig
    returnvalue = 1
1953 c51ffffe Klaus Aehlig
1954 3b31c9da Klaus Aehlig
  _RunCommandAndReport(["rm", "-f", pathutils.INTENT_TO_UPGRADE])
1955 c51ffffe Klaus Aehlig
1956 c51ffffe Klaus Aehlig
  ToStdout("Verifying cluster.")
1957 c51ffffe Klaus Aehlig
  if not _RunCommandAndReport(["gnt-cluster", "verify"]):
1958 c51ffffe Klaus Aehlig
    returnvalue = 1
1959 c51ffffe Klaus Aehlig
1960 c51ffffe Klaus Aehlig
  return returnvalue
1961 c51ffffe Klaus Aehlig
1962 c51ffffe Klaus Aehlig
1963 6c2a735a Klaus Aehlig
def UpgradeGanetiCommand(opts, args):
1964 6c2a735a Klaus Aehlig
  """Upgrade a cluster to a new ganeti version.
1965 6c2a735a Klaus Aehlig

1966 6c2a735a Klaus Aehlig
  @param opts: the command line options selected by the user
1967 6c2a735a Klaus Aehlig
  @type args: list
1968 6c2a735a Klaus Aehlig
  @param args: should be an empty list
1969 6c2a735a Klaus Aehlig
  @rtype: int
1970 6c2a735a Klaus Aehlig
  @return: the desired exit code
1971 6c2a735a Klaus Aehlig

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