Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_cluster.py @ 364c350f

History | View | Annotate | Download (52.2 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 b3989551 Iustin Pop
import os.path
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 78e706bb Michael Hanselmann
from ganeti import pathutils
47 66d1f035 René Nussbaumer
48 66d1f035 René Nussbaumer
49 66d1f035 René Nussbaumer
ON_OPT = cli_option("--on", default=False,
50 66d1f035 René Nussbaumer
                    action="store_true", dest="on",
51 66d1f035 René Nussbaumer
                    help="Recover from an EPO")
52 66d1f035 René Nussbaumer
53 66d1f035 René Nussbaumer
GROUPS_OPT = cli_option("--groups", default=False,
54 5ae4945a Iustin Pop
                        action="store_true", dest="groups",
55 5ae4945a Iustin Pop
                        help="Arguments are node groups instead of nodes")
56 66d1f035 René Nussbaumer
57 6022a419 Iustin Pop
FORCE_FAILOVER = cli_option("--yes-do-it", dest="yes_do_it",
58 6022a419 Iustin Pop
                            help="Override interactive check for --no-voting",
59 6022a419 Iustin Pop
                            default=False, action="store_true")
60 6022a419 Iustin Pop
61 66d1f035 René Nussbaumer
_EPO_PING_INTERVAL = 30 # 30 seconds between pings
62 66d1f035 René Nussbaumer
_EPO_PING_TIMEOUT = 1 # 1 second
63 66d1f035 René Nussbaumer
_EPO_REACHABLE_TIMEOUT = 15 * 60 # 15 minutes
64 a8083063 Iustin Pop
65 a8083063 Iustin Pop
66 4331f6cd Michael Hanselmann
@UsesRPC
67 a8083063 Iustin Pop
def InitCluster(opts, args):
68 a8083063 Iustin Pop
  """Initialize the cluster.
69 a8083063 Iustin Pop

70 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
71 469ee405 Iustin Pop
  @type args: list
72 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
73 469ee405 Iustin Pop
      cluster name
74 469ee405 Iustin Pop
  @rtype: int
75 469ee405 Iustin Pop
  @return: the desired exit code
76 a8083063 Iustin Pop

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

243 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
244 469ee405 Iustin Pop
  @type args: list
245 469ee405 Iustin Pop
  @param args: should be an empty list
246 469ee405 Iustin Pop
  @rtype: int
247 469ee405 Iustin Pop
  @return: the desired exit code
248 098c0958 Michael Hanselmann

249 a8083063 Iustin Pop
  """
250 a8083063 Iustin Pop
  if not opts.yes_do_it:
251 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
252 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
253 a8083063 Iustin Pop
    return 1
254 a8083063 Iustin Pop
255 c6d43e9e Iustin Pop
  op = opcodes.OpClusterDestroy()
256 400ca2f7 Iustin Pop
  master = SubmitOpCode(op, opts=opts)
257 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
258 140aa4a8 Iustin Pop
  # shutdown all the daemons
259 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
260 a8083063 Iustin Pop
  return 0
261 a8083063 Iustin Pop
262 a8083063 Iustin Pop
263 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
264 07bd8a51 Iustin Pop
  """Rename the cluster.
265 07bd8a51 Iustin Pop

266 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
267 469ee405 Iustin Pop
  @type args: list
268 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
269 469ee405 Iustin Pop
  @rtype: int
270 469ee405 Iustin Pop
  @return: the desired exit code
271 07bd8a51 Iustin Pop

272 07bd8a51 Iustin Pop
  """
273 6a016df9 Michael Hanselmann
  cl = GetClient()
274 6a016df9 Michael Hanselmann
275 6a016df9 Michael Hanselmann
  (cluster_name, ) = cl.QueryConfigValues(["cluster_name"])
276 6a016df9 Michael Hanselmann
277 6a016df9 Michael Hanselmann
  new_name = args[0]
278 07bd8a51 Iustin Pop
  if not opts.force:
279 6a016df9 Michael Hanselmann
    usertext = ("This will rename the cluster from '%s' to '%s'. If you are"
280 6a016df9 Michael Hanselmann
                " connected over the network to the cluster name, the"
281 6a016df9 Michael Hanselmann
                " operation is very dangerous as the IP address will be"
282 6a016df9 Michael Hanselmann
                " removed from the node and the change may not go through."
283 6a016df9 Michael Hanselmann
                " Continue?") % (cluster_name, new_name)
284 47988778 Iustin Pop
    if not AskUser(usertext):
285 07bd8a51 Iustin Pop
      return 1
286 07bd8a51 Iustin Pop
287 e126df25 Iustin Pop
  op = opcodes.OpClusterRename(name=new_name)
288 6a016df9 Michael Hanselmann
  result = SubmitOpCode(op, opts=opts, cl=cl)
289 6a016df9 Michael Hanselmann
290 48418fea Iustin Pop
  if result:
291 48418fea Iustin Pop
    ToStdout("Cluster renamed from '%s' to '%s'", cluster_name, result)
292 6a016df9 Michael Hanselmann
293 07bd8a51 Iustin Pop
  return 0
294 07bd8a51 Iustin Pop
295 07bd8a51 Iustin Pop
296 fb926117 Andrea Spadaccini
def ActivateMasterIp(opts, args):
297 fb926117 Andrea Spadaccini
  """Activates the master IP.
298 fb926117 Andrea Spadaccini

299 fb926117 Andrea Spadaccini
  """
300 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterActivateMasterIp()
301 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
302 fb926117 Andrea Spadaccini
  return 0
303 fb926117 Andrea Spadaccini
304 fb926117 Andrea Spadaccini
305 fb926117 Andrea Spadaccini
def DeactivateMasterIp(opts, args):
306 fb926117 Andrea Spadaccini
  """Deactivates the master IP.
307 fb926117 Andrea Spadaccini

308 fb926117 Andrea Spadaccini
  """
309 fb926117 Andrea Spadaccini
  if not opts.confirm:
310 fb926117 Andrea Spadaccini
    usertext = ("This will disable the master IP. All the open connections to"
311 fb926117 Andrea Spadaccini
                " the master IP will be closed. To reach the master you will"
312 fb926117 Andrea Spadaccini
                " need to use its node IP."
313 fb926117 Andrea Spadaccini
                " Continue?")
314 fb926117 Andrea Spadaccini
    if not AskUser(usertext):
315 fb926117 Andrea Spadaccini
      return 1
316 fb926117 Andrea Spadaccini
317 fb926117 Andrea Spadaccini
  op = opcodes.OpClusterDeactivateMasterIp()
318 fb926117 Andrea Spadaccini
  SubmitOpCode(op)
319 fb926117 Andrea Spadaccini
  return 0
320 fb926117 Andrea Spadaccini
321 fb926117 Andrea Spadaccini
322 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
323 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
324 afee0879 Iustin Pop

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

331 afee0879 Iustin Pop
  """
332 d1240007 Iustin Pop
  op = opcodes.OpClusterRedistConf()
333 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
334 afee0879 Iustin Pop
  return 0
335 afee0879 Iustin Pop
336 afee0879 Iustin Pop
337 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
338 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
339 a8083063 Iustin Pop

340 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
341 469ee405 Iustin Pop
  @type args: list
342 469ee405 Iustin Pop
  @param args: should be an empty list
343 469ee405 Iustin Pop
  @rtype: int
344 469ee405 Iustin Pop
  @return: the desired exit code
345 a8083063 Iustin Pop

346 a8083063 Iustin Pop
  """
347 42ab9ac4 Iustin Pop
  cl = GetClient(query=True)
348 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
349 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
350 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
351 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
352 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
353 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
354 026f444f Thomas Thrainer
  ToStdout("VCS version: %s", result["vcs_version"])
355 a8083063 Iustin Pop
  return 0
356 a8083063 Iustin Pop
357 a8083063 Iustin Pop
358 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
359 a8083063 Iustin Pop
  """Write name of master node to the standard output.
360 a8083063 Iustin Pop

361 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
362 469ee405 Iustin Pop
  @type args: list
363 469ee405 Iustin Pop
  @param args: should be an empty list
364 469ee405 Iustin Pop
  @rtype: int
365 469ee405 Iustin Pop
  @return: the desired exit code
366 a8083063 Iustin Pop

367 a8083063 Iustin Pop
  """
368 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
369 8eb148ae Iustin Pop
  ToStdout(master)
370 a8083063 Iustin Pop
  return 0
371 a8083063 Iustin Pop
372 cac599f1 Michael Hanselmann
373 0e79564a Bernardo Dal Seno
def _FormatGroupedParams(paramsdict, roman=False):
374 0e79564a Bernardo Dal Seno
  """Format Grouped parameters (be, nic, disk) by group.
375 1094acda Guido Trotter

376 1094acda Guido Trotter
  @type paramsdict: dict of dicts
377 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
378 0e79564a Bernardo Dal Seno
  @rtype: dict of dicts
379 0e79564a Bernardo Dal Seno
  @return: copy of the input dictionaries with strings as values
380 1094acda Guido Trotter

381 1094acda Guido Trotter
  """
382 0e79564a Bernardo Dal Seno
  ret = {}
383 0e79564a Bernardo Dal Seno
  for (item, val) in paramsdict.items():
384 664a9d73 René Nussbaumer
    if isinstance(val, dict):
385 0e79564a Bernardo Dal Seno
      ret[item] = _FormatGroupedParams(val, roman=roman)
386 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
387 0e79564a Bernardo Dal Seno
      ret[item] = compat.TryToRoman(val)
388 664a9d73 René Nussbaumer
    else:
389 0e79564a Bernardo Dal Seno
      ret[item] = str(val)
390 0e79564a Bernardo Dal Seno
  return ret
391 a8083063 Iustin Pop
392 cac599f1 Michael Hanselmann
393 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
394 a8083063 Iustin Pop
  """Shows cluster information.
395 a8083063 Iustin Pop

396 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
397 469ee405 Iustin Pop
  @type args: list
398 469ee405 Iustin Pop
  @param args: should be an empty list
399 469ee405 Iustin Pop
  @rtype: int
400 469ee405 Iustin Pop
  @return: the desired exit code
401 469ee405 Iustin Pop

402 a8083063 Iustin Pop
  """
403 a2160e57 Iustin Pop
  cl = GetClient(query=True)
404 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
405 a8083063 Iustin Pop
406 c118d1f4 Michael Hanselmann
  if result["tags"]:
407 1f864b60 Iustin Pop
    tags = utils.CommaJoin(utils.NiceSort(result["tags"]))
408 c118d1f4 Michael Hanselmann
  else:
409 c118d1f4 Michael Hanselmann
    tags = "(none)"
410 5a3ab484 Iustin Pop
  if result["reserved_lvs"]:
411 5a3ab484 Iustin Pop
    reserved_lvs = utils.CommaJoin(result["reserved_lvs"])
412 5a3ab484 Iustin Pop
  else:
413 5a3ab484 Iustin Pop
    reserved_lvs = "(none)"
414 be499e31 Agata Murawska
415 df5e2a28 Klaus Aehlig
  enabled_hv = result["enabled_hypervisors"]
416 df5e2a28 Klaus Aehlig
  hvparams = dict((k, v) for k, v in result["hvparams"].iteritems()
417 df5e2a28 Klaus Aehlig
                  if k in enabled_hv)
418 df5e2a28 Klaus Aehlig
419 0e79564a Bernardo Dal Seno
  info = [
420 0e79564a Bernardo Dal Seno
    ("Cluster name", result["name"]),
421 0e79564a Bernardo Dal Seno
    ("Cluster UUID", result["uuid"]),
422 0e79564a Bernardo Dal Seno
423 0e79564a Bernardo Dal Seno
    ("Creation time", utils.FormatTime(result["ctime"])),
424 0e79564a Bernardo Dal Seno
    ("Modification time", utils.FormatTime(result["mtime"])),
425 0e79564a Bernardo Dal Seno
426 0e79564a Bernardo Dal Seno
    ("Master node", result["master"]),
427 0e79564a Bernardo Dal Seno
428 0e79564a Bernardo Dal Seno
    ("Architecture (this node)",
429 0e79564a Bernardo Dal Seno
     "%s (%s)" % (result["architecture"][0], result["architecture"][1])),
430 0e79564a Bernardo Dal Seno
431 0e79564a Bernardo Dal Seno
    ("Tags", tags),
432 0e79564a Bernardo Dal Seno
433 0e79564a Bernardo Dal Seno
    ("Default hypervisor", result["default_hypervisor"]),
434 df5e2a28 Klaus Aehlig
    ("Enabled hypervisors", utils.CommaJoin(enabled_hv)),
435 0e79564a Bernardo Dal Seno
436 df5e2a28 Klaus Aehlig
    ("Hypervisor parameters", _FormatGroupedParams(hvparams)),
437 0e79564a Bernardo Dal Seno
438 0e79564a Bernardo Dal Seno
    ("OS-specific hypervisor parameters",
439 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["os_hvp"])),
440 0e79564a Bernardo Dal Seno
441 0e79564a Bernardo Dal Seno
    ("OS parameters", _FormatGroupedParams(result["osparams"])),
442 0e79564a Bernardo Dal Seno
443 0e79564a Bernardo Dal Seno
    ("Hidden OSes", utils.CommaJoin(result["hidden_os"])),
444 0e79564a Bernardo Dal Seno
    ("Blacklisted OSes", utils.CommaJoin(result["blacklisted_os"])),
445 0e79564a Bernardo Dal Seno
446 0e79564a Bernardo Dal Seno
    ("Cluster parameters", [
447 0e79564a Bernardo Dal Seno
      ("candidate pool size",
448 0e79564a Bernardo Dal Seno
       compat.TryToRoman(result["candidate_pool_size"],
449 0e79564a Bernardo Dal Seno
                         convert=opts.roman_integers)),
450 0e79564a Bernardo Dal Seno
      ("master netdev", result["master_netdev"]),
451 0e79564a Bernardo Dal Seno
      ("master netmask", result["master_netmask"]),
452 0e79564a Bernardo Dal Seno
      ("use external master IP address setup script",
453 0e79564a Bernardo Dal Seno
       result["use_external_mip_script"]),
454 0e79564a Bernardo Dal Seno
      ("lvm volume group", result["volume_group_name"]),
455 0e79564a Bernardo Dal Seno
      ("lvm reserved volumes", reserved_lvs),
456 0e79564a Bernardo Dal Seno
      ("drbd usermode helper", result["drbd_usermode_helper"]),
457 0e79564a Bernardo Dal Seno
      ("file storage path", result["file_storage_dir"]),
458 0e79564a Bernardo Dal Seno
      ("shared file storage path", result["shared_file_storage_dir"]),
459 0e79564a Bernardo Dal Seno
      ("maintenance of node health", result["maintain_node_health"]),
460 0e79564a Bernardo Dal Seno
      ("uid pool", uidpool.FormatUidPool(result["uid_pool"])),
461 0e79564a Bernardo Dal Seno
      ("default instance allocator", result["default_iallocator"]),
462 0e79564a Bernardo Dal Seno
      ("primary ip version", result["primary_ip_version"]),
463 0e79564a Bernardo Dal Seno
      ("preallocation wipe disks", result["prealloc_wipe_disks"]),
464 0e79564a Bernardo Dal Seno
      ("OS search path", utils.CommaJoin(pathutils.OS_SEARCH_PATH)),
465 0e79564a Bernardo Dal Seno
      ("ExtStorage Providers search path",
466 0e79564a Bernardo Dal Seno
       utils.CommaJoin(pathutils.ES_SEARCH_PATH)),
467 966e1580 Helga Velroyen
      ("enabled disk templates",
468 966e1580 Helga Velroyen
       utils.CommaJoin(result["enabled_disk_templates"])),
469 0e79564a Bernardo Dal Seno
      ]),
470 0e79564a Bernardo Dal Seno
471 0e79564a Bernardo Dal Seno
    ("Default node parameters",
472 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["ndparams"], roman=opts.roman_integers)),
473 0e79564a Bernardo Dal Seno
474 0e79564a Bernardo Dal Seno
    ("Default instance parameters",
475 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["beparams"], roman=opts.roman_integers)),
476 0e79564a Bernardo Dal Seno
477 0e79564a Bernardo Dal Seno
    ("Default nic parameters",
478 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["nicparams"], roman=opts.roman_integers)),
479 0e79564a Bernardo Dal Seno
480 0e79564a Bernardo Dal Seno
    ("Default disk parameters",
481 0e79564a Bernardo Dal Seno
     _FormatGroupedParams(result["diskparams"], roman=opts.roman_integers)),
482 0e79564a Bernardo Dal Seno
483 0e79564a Bernardo Dal Seno
    ("Instance policy - limits for instances",
484 d00884a2 Bernardo Dal Seno
     FormatPolicyInfo(result["ipolicy"], None, True)),
485 0e79564a Bernardo Dal Seno
    ]
486 0e79564a Bernardo Dal Seno
487 0e79564a Bernardo Dal Seno
  PrintGenericInfo(info)
488 a8083063 Iustin Pop
  return 0
489 a8083063 Iustin Pop
490 a8083063 Iustin Pop
491 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
492 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
493 a8083063 Iustin Pop

494 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
495 469ee405 Iustin Pop
  @type args: list
496 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
497 469ee405 Iustin Pop
      the file to be copied
498 469ee405 Iustin Pop
  @rtype: int
499 469ee405 Iustin Pop
  @return: the desired exit code
500 a8083063 Iustin Pop

501 a8083063 Iustin Pop
  """
502 b3989551 Iustin Pop
  filename = args[0]
503 b3989551 Iustin Pop
  if not os.path.exists(filename):
504 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
505 debac808 Iustin Pop
                               errors.ECODE_INVAL)
506 b3989551 Iustin Pop
507 56bece1f Iustin Pop
  cl = GetClient()
508 56bece1f Iustin Pop
509 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
510 56bece1f Iustin Pop
511 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
512 b6e88032 Michael Hanselmann
                           secondary_ips=opts.use_replication_network,
513 b6e88032 Michael Hanselmann
                           nodegroup=opts.nodegroup)
514 e00ea635 Michael Hanselmann
515 224ff0f7 Michael Hanselmann
  srun = ssh.SshRunner(cluster_name)
516 b3989551 Iustin Pop
  for node in results:
517 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
518 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
519 b3989551 Iustin Pop
520 a8083063 Iustin Pop
  return 0
521 a8083063 Iustin Pop
522 a8083063 Iustin Pop
523 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
524 a8083063 Iustin Pop
  """Run a command on some nodes.
525 a8083063 Iustin Pop

526 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
527 469ee405 Iustin Pop
  @type args: list
528 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
529 469ee405 Iustin Pop
  @rtype: int
530 469ee405 Iustin Pop
  @return: the desired exit code
531 a8083063 Iustin Pop

532 a8083063 Iustin Pop
  """
533 56bece1f Iustin Pop
  cl = GetClient()
534 7688d0d3 Michael Hanselmann
535 a8083063 Iustin Pop
  command = " ".join(args)
536 4040a784 Iustin Pop
537 b6e88032 Michael Hanselmann
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl, nodegroup=opts.nodegroup)
538 56bece1f Iustin Pop
539 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
540 56bece1f Iustin Pop
                                                    "master_node"])
541 b3989551 Iustin Pop
542 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
543 b3989551 Iustin Pop
544 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
545 b3989551 Iustin Pop
  if master_node in nodes:
546 b3989551 Iustin Pop
    nodes.remove(master_node)
547 b3989551 Iustin Pop
    nodes.append(master_node)
548 b3989551 Iustin Pop
549 b3989551 Iustin Pop
  for name in nodes:
550 052783ff Michael Hanselmann
    result = srun.Run(name, constants.SSH_LOGIN_USER, command)
551 d5b031dc Michael Hanselmann
552 d5b031dc Michael Hanselmann
    if opts.failure_only and result.exit_code == constants.EXIT_SUCCESS:
553 d5b031dc Michael Hanselmann
      # Do not output anything for successful commands
554 d5b031dc Michael Hanselmann
      continue
555 d5b031dc Michael Hanselmann
556 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
557 a24aed2a Michael Hanselmann
    if opts.show_machine_names:
558 a24aed2a Michael Hanselmann
      for line in result.output.splitlines():
559 a24aed2a Michael Hanselmann
        ToStdout("%s: %s", name, line)
560 a24aed2a Michael Hanselmann
    else:
561 a24aed2a Michael Hanselmann
      ToStdout("node: %s", name)
562 a24aed2a Michael Hanselmann
      ToStdout("%s", result.output)
563 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
564 b3989551 Iustin Pop
565 b3989551 Iustin Pop
  return 0
566 a8083063 Iustin Pop
567 a8083063 Iustin Pop
568 a8083063 Iustin Pop
def VerifyCluster(opts, args):
569 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
570 a8083063 Iustin Pop

571 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
572 469ee405 Iustin Pop
  @type args: list
573 469ee405 Iustin Pop
  @param args: should be an empty list
574 469ee405 Iustin Pop
  @rtype: int
575 469ee405 Iustin Pop
  @return: the desired exit code
576 a8083063 Iustin Pop

577 a8083063 Iustin Pop
  """
578 8d59409f Iustin Pop
  skip_checks = []
579 bf93ae69 Adeodato Simo
580 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
581 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
582 bf93ae69 Adeodato Simo
583 fcad7225 Michael Hanselmann
  cl = GetClient()
584 bf93ae69 Adeodato Simo
585 fcad7225 Michael Hanselmann
  op = opcodes.OpClusterVerify(verbose=opts.verbose,
586 fcad7225 Michael Hanselmann
                               error_codes=opts.error_codes,
587 fcad7225 Michael Hanselmann
                               debug_simulate_errors=opts.simulate_errors,
588 fcad7225 Michael Hanselmann
                               skip_checks=skip_checks,
589 93f2399e Andrea Spadaccini
                               ignore_errors=opts.ignore_errors,
590 fcad7225 Michael Hanselmann
                               group_name=opts.nodegroup)
591 fcad7225 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
592 bf93ae69 Adeodato Simo
593 fcad7225 Michael Hanselmann
  # Keep track of submitted jobs
594 fcad7225 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
595 fcad7225 Michael Hanselmann
596 fcad7225 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
597 fcad7225 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
598 bf93ae69 Adeodato Simo
599 fcad7225 Michael Hanselmann
  results = jex.GetResults()
600 ebe6cf38 Michael Hanselmann
601 ebe6cf38 Michael Hanselmann
  (bad_jobs, bad_results) = \
602 ebe6cf38 Michael Hanselmann
    map(len,
603 ebe6cf38 Michael Hanselmann
        # Convert iterators to lists
604 ebe6cf38 Michael Hanselmann
        map(list,
605 ebe6cf38 Michael Hanselmann
            # Count errors
606 ebe6cf38 Michael Hanselmann
            map(compat.partial(itertools.ifilterfalse, bool),
607 ebe6cf38 Michael Hanselmann
                # Convert result to booleans in a tuple
608 ebe6cf38 Michael Hanselmann
                zip(*((job_success, len(op_results) == 1 and op_results[0])
609 ebe6cf38 Michael Hanselmann
                      for (job_success, op_results) in results)))))
610 ebe6cf38 Michael Hanselmann
611 ebe6cf38 Michael Hanselmann
  if bad_jobs == 0 and bad_results == 0:
612 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
613 e0508c86 Guido Trotter
  else:
614 fcad7225 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
615 ebe6cf38 Michael Hanselmann
    if bad_jobs > 0:
616 ebe6cf38 Michael Hanselmann
      ToStdout("%s job(s) failed while verifying the cluster.", bad_jobs)
617 fcad7225 Michael Hanselmann
618 fcad7225 Michael Hanselmann
  return rcode
619 a8083063 Iustin Pop
620 a8083063 Iustin Pop
621 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
622 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
623 f4d4e184 Iustin Pop

624 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
625 469ee405 Iustin Pop
  @type args: list
626 469ee405 Iustin Pop
  @param args: should be an empty list
627 469ee405 Iustin Pop
  @rtype: int
628 469ee405 Iustin Pop
  @return: the desired exit code
629 f4d4e184 Iustin Pop

630 f4d4e184 Iustin Pop
  """
631 f1b083ce Michael Hanselmann
  cl = GetClient()
632 f1b083ce Michael Hanselmann
633 bd8210a7 Iustin Pop
  op = opcodes.OpClusterVerifyDisks()
634 f4d4e184 Iustin Pop
635 ae1a845c Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
636 ae1a845c Michael Hanselmann
637 ae1a845c Michael Hanselmann
  # Keep track of submitted jobs
638 ae1a845c Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
639 ae1a845c Michael Hanselmann
640 ae1a845c Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
641 ae1a845c Michael Hanselmann
    jex.AddJobId(None, status, job_id)
642 b63ed789 Iustin Pop
643 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
644 b63ed789 Iustin Pop
645 ae1a845c Michael Hanselmann
  for (status, result) in jex.GetResults():
646 ae1a845c Michael Hanselmann
    if not status:
647 ae1a845c Michael Hanselmann
      ToStdout("Job failed: %s", result)
648 ae1a845c Michael Hanselmann
      continue
649 ae1a845c Michael Hanselmann
650 ae1a845c Michael Hanselmann
    ((bad_nodes, instances, missing), ) = result
651 ae1a845c Michael Hanselmann
652 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
653 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
654 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
655 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
656 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
657 b63ed789 Iustin Pop
658 f4d4e184 Iustin Pop
    for iname in instances:
659 b63ed789 Iustin Pop
      if iname in missing:
660 b63ed789 Iustin Pop
        continue
661 83f5d475 Iustin Pop
      op = opcodes.OpInstanceActivateDisks(instance_name=iname)
662 f4d4e184 Iustin Pop
      try:
663 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
664 f1b083ce Michael Hanselmann
        SubmitOpCode(op, opts=opts, cl=cl)
665 f4d4e184 Iustin Pop
      except errors.GenericError, err:
666 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
667 f4d4e184 Iustin Pop
        retcode |= nret
668 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
669 b63ed789 Iustin Pop
670 ae1a845c Michael Hanselmann
    if missing:
671 ae1a845c Michael Hanselmann
      for iname, ival in missing.iteritems():
672 ae1a845c Michael Hanselmann
        all_missing = compat.all(x[0] in bad_nodes for x in ival)
673 ae1a845c Michael Hanselmann
        if all_missing:
674 ae1a845c Michael Hanselmann
          ToStdout("Instance %s cannot be verified as it lives on"
675 ae1a845c Michael Hanselmann
                   " broken nodes", iname)
676 ae1a845c Michael Hanselmann
        else:
677 ae1a845c Michael Hanselmann
          ToStdout("Instance %s has missing logical volumes:", iname)
678 ae1a845c Michael Hanselmann
          ival.sort()
679 ae1a845c Michael Hanselmann
          for node, vol in ival:
680 ae1a845c Michael Hanselmann
            if node in bad_nodes:
681 ae1a845c Michael Hanselmann
              ToStdout("\tbroken node %s /dev/%s", node, vol)
682 ae1a845c Michael Hanselmann
            else:
683 ae1a845c Michael Hanselmann
              ToStdout("\t%s /dev/%s", node, vol)
684 ae1a845c Michael Hanselmann
685 ae1a845c Michael Hanselmann
      ToStdout("You need to replace or recreate disks for all the above"
686 ae1a845c Michael Hanselmann
               " instances if this message persists after fixing broken nodes.")
687 ae1a845c Michael Hanselmann
      retcode = constants.EXIT_FAILURE
688 9b99be28 Michael Hanselmann
    elif not instances:
689 9b99be28 Michael Hanselmann
      ToStdout("No disks need to be activated.")
690 f4d4e184 Iustin Pop
691 f4d4e184 Iustin Pop
  return retcode
692 f4d4e184 Iustin Pop
693 f4d4e184 Iustin Pop
694 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
695 60975797 Iustin Pop
  """Verify sizes of cluster disks.
696 60975797 Iustin Pop

697 60975797 Iustin Pop
  @param opts: the command line options selected by the user
698 60975797 Iustin Pop
  @type args: list
699 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
700 60975797 Iustin Pop
  @rtype: int
701 60975797 Iustin Pop
  @return: the desired exit code
702 60975797 Iustin Pop

703 60975797 Iustin Pop
  """
704 5d01aca3 Iustin Pop
  op = opcodes.OpClusterRepairDiskSizes(instances=args)
705 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
706 60975797 Iustin Pop
707 60975797 Iustin Pop
708 4331f6cd Michael Hanselmann
@UsesRPC
709 a8083063 Iustin Pop
def MasterFailover(opts, args):
710 a8083063 Iustin Pop
  """Failover the master node.
711 a8083063 Iustin Pop

712 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
713 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
714 a8083063 Iustin Pop
  master.
715 a8083063 Iustin Pop

716 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
717 469ee405 Iustin Pop
  @type args: list
718 469ee405 Iustin Pop
  @param args: should be an empty list
719 469ee405 Iustin Pop
  @rtype: int
720 469ee405 Iustin Pop
  @return: the desired exit code
721 469ee405 Iustin Pop

722 a8083063 Iustin Pop
  """
723 6022a419 Iustin Pop
  if opts.no_voting and not opts.yes_do_it:
724 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
725 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
726 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
727 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
728 8e2524c3 Guido Trotter
    if not AskUser(usertext):
729 8e2524c3 Guido Trotter
      return 1
730 8e2524c3 Guido Trotter
731 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
732 a8083063 Iustin Pop
733 a8083063 Iustin Pop
734 4404ffad Iustin Pop
def MasterPing(opts, args):
735 4404ffad Iustin Pop
  """Checks if the master is alive.
736 4404ffad Iustin Pop

737 4404ffad Iustin Pop
  @param opts: the command line options selected by the user
738 4404ffad Iustin Pop
  @type args: list
739 4404ffad Iustin Pop
  @param args: should be an empty list
740 4404ffad Iustin Pop
  @rtype: int
741 4404ffad Iustin Pop
  @return: the desired exit code
742 4404ffad Iustin Pop

743 4404ffad Iustin Pop
  """
744 4404ffad Iustin Pop
  try:
745 4404ffad Iustin Pop
    cl = GetClient()
746 4404ffad Iustin Pop
    cl.QueryClusterInfo()
747 4404ffad Iustin Pop
    return 0
748 b459a848 Andrea Spadaccini
  except Exception: # pylint: disable=W0703
749 4404ffad Iustin Pop
    return 1
750 4404ffad Iustin Pop
751 4404ffad Iustin Pop
752 73415719 Iustin Pop
def SearchTags(opts, args):
753 73415719 Iustin Pop
  """Searches the tags on all the cluster.
754 73415719 Iustin Pop

755 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
756 469ee405 Iustin Pop
  @type args: list
757 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
758 469ee405 Iustin Pop
  @rtype: int
759 469ee405 Iustin Pop
  @return: the desired exit code
760 469ee405 Iustin Pop

761 73415719 Iustin Pop
  """
762 715462e7 Iustin Pop
  op = opcodes.OpTagsSearch(pattern=args[0])
763 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
764 73415719 Iustin Pop
  if not result:
765 73415719 Iustin Pop
    return 1
766 73415719 Iustin Pop
  result = list(result)
767 73415719 Iustin Pop
  result.sort()
768 73415719 Iustin Pop
  for path, tag in result:
769 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
770 73415719 Iustin Pop
771 73415719 Iustin Pop
772 b6267745 Andrea Spadaccini
def _ReadAndVerifyCert(cert_filename, verify_private_key=False):
773 b6267745 Andrea Spadaccini
  """Reads and verifies an X509 certificate.
774 b6267745 Andrea Spadaccini

775 b6267745 Andrea Spadaccini
  @type cert_filename: string
776 b6267745 Andrea Spadaccini
  @param cert_filename: the path of the file containing the certificate to
777 b6267745 Andrea Spadaccini
                        verify encoded in PEM format
778 b6267745 Andrea Spadaccini
  @type verify_private_key: bool
779 b6267745 Andrea Spadaccini
  @param verify_private_key: whether to verify the private key in addition to
780 b6267745 Andrea Spadaccini
                             the public certificate
781 b6267745 Andrea Spadaccini
  @rtype: string
782 b6267745 Andrea Spadaccini
  @return: a string containing the PEM-encoded certificate.
783 b6267745 Andrea Spadaccini

784 b6267745 Andrea Spadaccini
  """
785 b6267745 Andrea Spadaccini
  try:
786 b6267745 Andrea Spadaccini
    pem = utils.ReadFile(cert_filename)
787 b6267745 Andrea Spadaccini
  except IOError, err:
788 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
789 b6267745 Andrea Spadaccini
                               "Unable to read certificate: %s" % str(err))
790 b6267745 Andrea Spadaccini
791 b6267745 Andrea Spadaccini
  try:
792 b6267745 Andrea Spadaccini
    OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, pem)
793 b6267745 Andrea Spadaccini
  except Exception, err:
794 b6267745 Andrea Spadaccini
    raise errors.X509CertError(cert_filename,
795 b6267745 Andrea Spadaccini
                               "Unable to load certificate: %s" % str(err))
796 b6267745 Andrea Spadaccini
797 b6267745 Andrea Spadaccini
  if verify_private_key:
798 b6267745 Andrea Spadaccini
    try:
799 b6267745 Andrea Spadaccini
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, pem)
800 b6267745 Andrea Spadaccini
    except Exception, err:
801 b6267745 Andrea Spadaccini
      raise errors.X509CertError(cert_filename,
802 b6267745 Andrea Spadaccini
                                 "Unable to load private key: %s" % str(err))
803 b6267745 Andrea Spadaccini
804 b6267745 Andrea Spadaccini
  return pem
805 b6267745 Andrea Spadaccini
806 b6267745 Andrea Spadaccini
807 5ae4945a Iustin Pop
def _RenewCrypto(new_cluster_cert, new_rapi_cert, # pylint: disable=R0911
808 b6267745 Andrea Spadaccini
                 rapi_cert_filename, new_spice_cert, spice_cert_filename,
809 b6267745 Andrea Spadaccini
                 spice_cacert_filename, new_confd_hmac_key, new_cds,
810 b6267745 Andrea Spadaccini
                 cds_filename, force):
811 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
812 6d4a1656 Michael Hanselmann

813 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
814 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
815 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
816 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
817 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
818 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
819 b6267745 Andrea Spadaccini
  @type new_spice_cert: bool
820 b6267745 Andrea Spadaccini
  @param new_spice_cert: Whether to generate a new SPICE certificate
821 b6267745 Andrea Spadaccini
  @type spice_cert_filename: string
822 b6267745 Andrea Spadaccini
  @param spice_cert_filename: Path to file containing new SPICE certificate
823 b6267745 Andrea Spadaccini
  @type spice_cacert_filename: string
824 b6267745 Andrea Spadaccini
  @param spice_cacert_filename: Path to file containing the certificate of the
825 b6267745 Andrea Spadaccini
                                CA that signed the SPICE certificate
826 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
827 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
828 3db3eb2a Michael Hanselmann
  @type new_cds: bool
829 3db3eb2a Michael Hanselmann
  @param new_cds: Whether to generate a new cluster domain secret
830 3db3eb2a Michael Hanselmann
  @type cds_filename: string
831 3db3eb2a Michael Hanselmann
  @param cds_filename: Path to file containing new cluster domain secret
832 6d4a1656 Michael Hanselmann
  @type force: bool
833 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
834 6d4a1656 Michael Hanselmann

835 6d4a1656 Michael Hanselmann
  """
836 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
837 6e060e15 Andrea Spadaccini
    ToStderr("Only one of the --new-rapi-certificate and --rapi-certificate"
838 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
839 6d4a1656 Michael Hanselmann
    return 1
840 6d4a1656 Michael Hanselmann
841 3db3eb2a Michael Hanselmann
  if new_cds and cds_filename:
842 3db3eb2a Michael Hanselmann
    ToStderr("Only one of the --new-cluster-domain-secret and"
843 3db3eb2a Michael Hanselmann
             " --cluster-domain-secret options can be specified at"
844 3db3eb2a Michael Hanselmann
             " the same time.")
845 3db3eb2a Michael Hanselmann
    return 1
846 3db3eb2a Michael Hanselmann
847 b6267745 Andrea Spadaccini
  if new_spice_cert and (spice_cert_filename or spice_cacert_filename):
848 b6267745 Andrea Spadaccini
    ToStderr("When using --new-spice-certificate, the --spice-certificate"
849 b6267745 Andrea Spadaccini
             " and --spice-ca-certificate must not be used.")
850 b6267745 Andrea Spadaccini
    return 1
851 6d4a1656 Michael Hanselmann
852 b6267745 Andrea Spadaccini
  if bool(spice_cacert_filename) ^ bool(spice_cert_filename):
853 b6267745 Andrea Spadaccini
    ToStderr("Both --spice-certificate and --spice-ca-certificate must be"
854 b6267745 Andrea Spadaccini
             " specified.")
855 b6267745 Andrea Spadaccini
    return 1
856 6d4a1656 Michael Hanselmann
857 b6267745 Andrea Spadaccini
  rapi_cert_pem, spice_cert_pem, spice_cacert_pem = (None, None, None)
858 b6267745 Andrea Spadaccini
  try:
859 b6267745 Andrea Spadaccini
    if rapi_cert_filename:
860 b6267745 Andrea Spadaccini
      rapi_cert_pem = _ReadAndVerifyCert(rapi_cert_filename, True)
861 b6267745 Andrea Spadaccini
    if spice_cert_filename:
862 b6267745 Andrea Spadaccini
      spice_cert_pem = _ReadAndVerifyCert(spice_cert_filename, True)
863 b6267745 Andrea Spadaccini
      spice_cacert_pem = _ReadAndVerifyCert(spice_cacert_filename)
864 b6267745 Andrea Spadaccini
  except errors.X509CertError, err:
865 b6267745 Andrea Spadaccini
    ToStderr("Unable to load X509 certificate from %s: %s", err[0], err[1])
866 b6267745 Andrea Spadaccini
    return 1
867 6d4a1656 Michael Hanselmann
868 3db3eb2a Michael Hanselmann
  if cds_filename:
869 3db3eb2a Michael Hanselmann
    try:
870 3db3eb2a Michael Hanselmann
      cds = utils.ReadFile(cds_filename)
871 b459a848 Andrea Spadaccini
    except Exception, err: # pylint: disable=W0703
872 3db3eb2a Michael Hanselmann
      ToStderr("Can't load new cluster domain secret from %s: %s" %
873 3db3eb2a Michael Hanselmann
               (cds_filename, str(err)))
874 3db3eb2a Michael Hanselmann
      return 1
875 3db3eb2a Michael Hanselmann
  else:
876 3db3eb2a Michael Hanselmann
    cds = None
877 3db3eb2a Michael Hanselmann
878 6d4a1656 Michael Hanselmann
  if not force:
879 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
880 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
881 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
882 6d4a1656 Michael Hanselmann
      return 1
883 6d4a1656 Michael Hanselmann
884 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
885 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
886 b6267745 Andrea Spadaccini
    bootstrap.GenerateClusterCrypto(new_cluster_cert,
887 b6267745 Andrea Spadaccini
                                    new_rapi_cert,
888 b6267745 Andrea Spadaccini
                                    new_spice_cert,
889 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
890 3db3eb2a Michael Hanselmann
                                    new_cds,
891 3db3eb2a Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem,
892 b6267745 Andrea Spadaccini
                                    spice_cert_pem=spice_cert_pem,
893 b6267745 Andrea Spadaccini
                                    spice_cacert_pem=spice_cacert_pem,
894 3db3eb2a Michael Hanselmann
                                    cds=cds)
895 6d4a1656 Michael Hanselmann
896 6d4a1656 Michael Hanselmann
    files_to_copy = []
897 6d4a1656 Michael Hanselmann
898 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
899 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.NODED_CERT_FILE)
900 6d4a1656 Michael Hanselmann
901 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
902 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.RAPI_CERT_FILE)
903 6d4a1656 Michael Hanselmann
904 b6267745 Andrea Spadaccini
    if new_spice_cert or spice_cert_pem:
905 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.SPICE_CERT_FILE)
906 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.SPICE_CACERT_FILE)
907 b6267745 Andrea Spadaccini
908 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
909 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.CONFD_HMAC_KEY)
910 6d4a1656 Michael Hanselmann
911 3db3eb2a Michael Hanselmann
    if new_cds or cds:
912 78e706bb Michael Hanselmann
      files_to_copy.append(pathutils.CLUSTER_DOMAIN_SECRET_FILE)
913 3db3eb2a Michael Hanselmann
914 6d4a1656 Michael Hanselmann
    if files_to_copy:
915 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
916 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
917 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
918 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
919 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
920 6d4a1656 Michael Hanselmann
921 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
922 6d4a1656 Michael Hanselmann
923 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
924 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
925 6d4a1656 Michael Hanselmann
926 6d4a1656 Michael Hanselmann
  return 0
927 6d4a1656 Michael Hanselmann
928 6d4a1656 Michael Hanselmann
929 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
930 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
931 6d4a1656 Michael Hanselmann

932 6d4a1656 Michael Hanselmann
  """
933 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
934 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
935 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
936 b6267745 Andrea Spadaccini
                      opts.new_spice_cert,
937 b6267745 Andrea Spadaccini
                      opts.spice_cert,
938 b6267745 Andrea Spadaccini
                      opts.spice_cacert,
939 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
940 3db3eb2a Michael Hanselmann
                      opts.new_cluster_domain_secret,
941 3db3eb2a Michael Hanselmann
                      opts.cluster_domain_secret,
942 6d4a1656 Michael Hanselmann
                      opts.force)
943 6d4a1656 Michael Hanselmann
944 6d4a1656 Michael Hanselmann
945 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
946 90b6aa3a Manuel Franceschini
  """Modify the cluster.
947 90b6aa3a Manuel Franceschini

948 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
949 469ee405 Iustin Pop
  @type args: list
950 469ee405 Iustin Pop
  @param args: should be an empty list
951 469ee405 Iustin Pop
  @rtype: int
952 469ee405 Iustin Pop
  @return: the desired exit code
953 90b6aa3a Manuel Franceschini

954 90b6aa3a Manuel Franceschini
  """
955 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
956 ed14ed48 Luca Bigliardi
          not opts.drbd_storage or opts.drbd_helper or
957 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
958 bc5d0215 Andrea Spadaccini
          opts.beparams or opts.nicparams or
959 bc5d0215 Andrea Spadaccini
          opts.ndparams or opts.diskparams or
960 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
961 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
962 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
963 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
964 bf4af505 Apollon Oikonomopoulos
          opts.remove_uids is not None or
965 f38ea602 Iustin Pop
          opts.default_iallocator is not None or
966 b883637f René Nussbaumer
          opts.reserved_lvs is not None or
967 38f9d2cf Guido Trotter
          opts.master_netdev is not None or
968 5a8648eb Andrea Spadaccini
          opts.master_netmask is not None or
969 bf689b7a Andrea Spadaccini
          opts.use_external_mip_script is not None or
970 2da9f556 René Nussbaumer
          opts.prealloc_wipe_disks is not None or
971 2da9f556 René Nussbaumer
          opts.hv_state or
972 66af5ec5 Helga Velroyen
          opts.enabled_disk_templates or
973 e1a6850f Agata Murawska
          opts.disk_state or
974 d2d3935a Bernardo Dal Seno
          opts.ipolicy_bounds_specs is not None or
975 d2d3935a Bernardo Dal Seno
          opts.ipolicy_std_specs is not None or
976 1e7acc3b Iustin Pop
          opts.ipolicy_disk_templates is not None or
977 31d827d1 René Nussbaumer
          opts.ipolicy_vcpu_ratio is not None or
978 75f2ff7d Michele Tartara
          opts.ipolicy_spindle_ratio is not None or
979 75f2ff7d Michele Tartara
          opts.modify_etc_hosts is not None):
980 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
981 90b6aa3a Manuel Franceschini
    return 1
982 90b6aa3a Manuel Franceschini
983 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
984 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
985 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
986 90b6aa3a Manuel Franceschini
    return 1
987 6d4a1656 Michael Hanselmann
988 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
989 6d4a1656 Michael Hanselmann
    vg_name = ""
990 90b6aa3a Manuel Franceschini
991 ed14ed48 Luca Bigliardi
  drbd_helper = opts.drbd_helper
992 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage and opts.drbd_helper:
993 ed14ed48 Luca Bigliardi
    ToStderr("Options --no-drbd-storage and --drbd-usermode-helper conflict.")
994 ed14ed48 Luca Bigliardi
    return 1
995 ed14ed48 Luca Bigliardi
996 ed14ed48 Luca Bigliardi
  if not opts.drbd_storage:
997 ed14ed48 Luca Bigliardi
    drbd_helper = ""
998 ed14ed48 Luca Bigliardi
999 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
1000 779c15bb Iustin Pop
  if hvlist is not None:
1001 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
1002 779c15bb Iustin Pop
1003 66af5ec5 Helga Velroyen
  enabled_disk_templates = opts.enabled_disk_templates
1004 66af5ec5 Helga Velroyen
  if enabled_disk_templates:
1005 66af5ec5 Helga Velroyen
    enabled_disk_templates = enabled_disk_templates.split(",")
1006 66af5ec5 Helga Velroyen
1007 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
1008 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
1009 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
1010 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
1011 779c15bb Iustin Pop
1012 bc5d0215 Andrea Spadaccini
  diskparams = dict(opts.diskparams)
1013 bc5d0215 Andrea Spadaccini
1014 c20a19ed Iustin Pop
  for dt_params in diskparams.values():
1015 bc5d0215 Andrea Spadaccini
    utils.ForceDictType(dt_params, constants.DISK_DT_TYPES)
1016 bc5d0215 Andrea Spadaccini
1017 779c15bb Iustin Pop
  beparams = opts.beparams
1018 b2e233a5 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_COMPAT)
1019 779c15bb Iustin Pop
1020 5af3da74 Guido Trotter
  nicparams = opts.nicparams
1021 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
1022 5af3da74 Guido Trotter
1023 6204ee71 René Nussbaumer
  ndparams = opts.ndparams
1024 6204ee71 René Nussbaumer
  if ndparams is not None:
1025 6204ee71 René Nussbaumer
    utils.ForceDictType(ndparams, constants.NDS_PARAMETER_TYPES)
1026 1338f2b4 Balazs Lecz
1027 703fa9ab Iustin Pop
  ipolicy = CreateIPolicyFromOpts(
1028 d2d3935a Bernardo Dal Seno
    minmax_ispecs=opts.ipolicy_bounds_specs,
1029 d2d3935a Bernardo Dal Seno
    std_ispecs=opts.ipolicy_std_specs,
1030 976b78ba Iustin Pop
    ipolicy_disk_templates=opts.ipolicy_disk_templates,
1031 976b78ba Iustin Pop
    ipolicy_vcpu_ratio=opts.ipolicy_vcpu_ratio,
1032 31d827d1 René Nussbaumer
    ipolicy_spindle_ratio=opts.ipolicy_spindle_ratio,
1033 976b78ba Iustin Pop
    )
1034 e1a6850f Agata Murawska
1035 3953242f Iustin Pop
  mnh = opts.maintain_node_health
1036 3953242f Iustin Pop
1037 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
1038 1338f2b4 Balazs Lecz
  if uid_pool is not None:
1039 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
1040 1338f2b4 Balazs Lecz
1041 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
1042 fdad8c4d Balazs Lecz
  if add_uids is not None:
1043 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
1044 fdad8c4d Balazs Lecz
1045 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
1046 fdad8c4d Balazs Lecz
  if remove_uids is not None:
1047 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
1048 fdad8c4d Balazs Lecz
1049 f38ea602 Iustin Pop
  if opts.reserved_lvs is not None:
1050 f38ea602 Iustin Pop
    if opts.reserved_lvs == "":
1051 f38ea602 Iustin Pop
      opts.reserved_lvs = []
1052 f38ea602 Iustin Pop
    else:
1053 f38ea602 Iustin Pop
      opts.reserved_lvs = utils.UnescapeAndSplit(opts.reserved_lvs, sep=",")
1054 f38ea602 Iustin Pop
1055 5a8648eb Andrea Spadaccini
  if opts.master_netmask is not None:
1056 5a8648eb Andrea Spadaccini
    try:
1057 5a8648eb Andrea Spadaccini
      opts.master_netmask = int(opts.master_netmask)
1058 5a8648eb Andrea Spadaccini
    except ValueError:
1059 5a8648eb Andrea Spadaccini
      ToStderr("The --master-netmask option expects an int parameter.")
1060 5a8648eb Andrea Spadaccini
      return 1
1061 5a8648eb Andrea Spadaccini
1062 bf689b7a Andrea Spadaccini
  ext_ip_script = opts.use_external_mip_script
1063 bf689b7a Andrea Spadaccini
1064 2da9f556 René Nussbaumer
  if opts.disk_state:
1065 2da9f556 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
1066 2da9f556 René Nussbaumer
  else:
1067 2da9f556 René Nussbaumer
    disk_state = {}
1068 2da9f556 René Nussbaumer
1069 2da9f556 René Nussbaumer
  hv_state = dict(opts.hv_state)
1070 2da9f556 René Nussbaumer
1071 c270ee07 Helga Velroyen
  op = opcodes.OpClusterSetParams(
1072 c270ee07 Helga Velroyen
    vg_name=vg_name,
1073 c270ee07 Helga Velroyen
    drbd_helper=drbd_helper,
1074 c270ee07 Helga Velroyen
    enabled_hypervisors=hvlist,
1075 c270ee07 Helga Velroyen
    hvparams=hvparams,
1076 c270ee07 Helga Velroyen
    os_hvp=None,
1077 c270ee07 Helga Velroyen
    beparams=beparams,
1078 c270ee07 Helga Velroyen
    nicparams=nicparams,
1079 c270ee07 Helga Velroyen
    ndparams=ndparams,
1080 c270ee07 Helga Velroyen
    diskparams=diskparams,
1081 c270ee07 Helga Velroyen
    ipolicy=ipolicy,
1082 c270ee07 Helga Velroyen
    candidate_pool_size=opts.candidate_pool_size,
1083 c270ee07 Helga Velroyen
    maintain_node_health=mnh,
1084 75f2ff7d Michele Tartara
    modify_etc_hosts=opts.modify_etc_hosts,
1085 c270ee07 Helga Velroyen
    uid_pool=uid_pool,
1086 c270ee07 Helga Velroyen
    add_uids=add_uids,
1087 c270ee07 Helga Velroyen
    remove_uids=remove_uids,
1088 c270ee07 Helga Velroyen
    default_iallocator=opts.default_iallocator,
1089 c270ee07 Helga Velroyen
    prealloc_wipe_disks=opts.prealloc_wipe_disks,
1090 c270ee07 Helga Velroyen
    master_netdev=opts.master_netdev,
1091 c270ee07 Helga Velroyen
    master_netmask=opts.master_netmask,
1092 c270ee07 Helga Velroyen
    reserved_lvs=opts.reserved_lvs,
1093 c270ee07 Helga Velroyen
    use_external_mip_script=ext_ip_script,
1094 c270ee07 Helga Velroyen
    hv_state=hv_state,
1095 c270ee07 Helga Velroyen
    disk_state=disk_state,
1096 66af5ec5 Helga Velroyen
    enabled_disk_templates=enabled_disk_templates,
1097 2f836021 Klaus Aehlig
    force=opts.force,
1098 c270ee07 Helga Velroyen
    )
1099 745dae57 Michael Hanselmann
  SubmitOrSend(op, opts)
1100 90b6aa3a Manuel Franceschini
  return 0
1101 90b6aa3a Manuel Franceschini
1102 90b6aa3a Manuel Franceschini
1103 3ccafd0e Iustin Pop
def QueueOps(opts, args):
1104 3ccafd0e Iustin Pop
  """Queue operations.
1105 3ccafd0e Iustin Pop

1106 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
1107 469ee405 Iustin Pop
  @type args: list
1108 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
1109 469ee405 Iustin Pop
  @rtype: int
1110 469ee405 Iustin Pop
  @return: the desired exit code
1111 469ee405 Iustin Pop

1112 3ccafd0e Iustin Pop
  """
1113 3ccafd0e Iustin Pop
  command = args[0]
1114 3ccafd0e Iustin Pop
  client = GetClient()
1115 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
1116 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
1117 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
1118 3ccafd0e Iustin Pop
  elif command == "info":
1119 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
1120 3ccafd0e Iustin Pop
    if result[0]:
1121 3a24c527 Iustin Pop
      val = "set"
1122 3ccafd0e Iustin Pop
    else:
1123 3a24c527 Iustin Pop
      val = "unset"
1124 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
1125 2e668b38 Guido Trotter
  else:
1126 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1127 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1128 2e668b38 Guido Trotter
1129 3ccafd0e Iustin Pop
  return 0
1130 3ccafd0e Iustin Pop
1131 95b2e626 Michael Hanselmann
1132 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
1133 28b498cd Michael Hanselmann
  if until is None or until < time.time():
1134 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
1135 28b498cd Michael Hanselmann
  else:
1136 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
1137 28b498cd Michael Hanselmann
1138 28b498cd Michael Hanselmann
1139 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
1140 95b2e626 Michael Hanselmann
  """Watcher operations.
1141 95b2e626 Michael Hanselmann

1142 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
1143 95b2e626 Michael Hanselmann
  @type args: list
1144 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
1145 95b2e626 Michael Hanselmann
  @rtype: int
1146 95b2e626 Michael Hanselmann
  @return: the desired exit code
1147 95b2e626 Michael Hanselmann

1148 95b2e626 Michael Hanselmann
  """
1149 95b2e626 Michael Hanselmann
  command = args[0]
1150 95b2e626 Michael Hanselmann
  client = GetClient()
1151 95b2e626 Michael Hanselmann
1152 95b2e626 Michael Hanselmann
  if command == "continue":
1153 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
1154 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
1155 95b2e626 Michael Hanselmann
1156 95b2e626 Michael Hanselmann
  elif command == "pause":
1157 95b2e626 Michael Hanselmann
    if len(args) < 2:
1158 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
1159 95b2e626 Michael Hanselmann
1160 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
1161 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
1162 95b2e626 Michael Hanselmann
1163 95b2e626 Michael Hanselmann
  elif command == "info":
1164 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
1165 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
1166 95b2e626 Michael Hanselmann
1167 95b2e626 Michael Hanselmann
  else:
1168 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
1169 debac808 Iustin Pop
                               errors.ECODE_INVAL)
1170 95b2e626 Michael Hanselmann
1171 95b2e626 Michael Hanselmann
  return 0
1172 95b2e626 Michael Hanselmann
1173 95b2e626 Michael Hanselmann
1174 66d1f035 René Nussbaumer
def _OobPower(opts, node_list, power):
1175 66d1f035 René Nussbaumer
  """Puts the node in the list to desired power state.
1176 66d1f035 René Nussbaumer

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

1182 66d1f035 René Nussbaumer
  """
1183 66d1f035 René Nussbaumer
  if power:
1184 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_ON
1185 66d1f035 René Nussbaumer
  else:
1186 66d1f035 René Nussbaumer
    command = constants.OOB_POWER_OFF
1187 66d1f035 René Nussbaumer
1188 66d1f035 René Nussbaumer
  op = opcodes.OpOobCommand(node_names=node_list,
1189 66d1f035 René Nussbaumer
                            command=command,
1190 66d1f035 René Nussbaumer
                            ignore_status=True,
1191 cfed3b9f René Nussbaumer
                            timeout=opts.oob_timeout,
1192 cfed3b9f René Nussbaumer
                            power_delay=opts.power_delay)
1193 66d1f035 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
1194 66d1f035 René Nussbaumer
  errs = 0
1195 66d1f035 René Nussbaumer
  for node_result in result:
1196 66d1f035 René Nussbaumer
    (node_tuple, data_tuple) = node_result
1197 66d1f035 René Nussbaumer
    (_, node_name) = node_tuple
1198 66d1f035 René Nussbaumer
    (data_status, _) = data_tuple
1199 66d1f035 René Nussbaumer
    if data_status != constants.RS_NORMAL:
1200 66d1f035 René Nussbaumer
      assert data_status != constants.RS_UNAVAIL
1201 66d1f035 René Nussbaumer
      errs += 1
1202 66d1f035 René Nussbaumer
      ToStderr("There was a problem changing power for %s, please investigate",
1203 66d1f035 René Nussbaumer
               node_name)
1204 66d1f035 René Nussbaumer
1205 66d1f035 René Nussbaumer
  if errs > 0:
1206 66d1f035 René Nussbaumer
    return False
1207 66d1f035 René Nussbaumer
1208 66d1f035 René Nussbaumer
  return True
1209 66d1f035 René Nussbaumer
1210 66d1f035 René Nussbaumer
1211 3e0ed18c René Nussbaumer
def _InstanceStart(opts, inst_list, start, no_remember=False):
1212 66d1f035 René Nussbaumer
  """Puts the instances in the list to desired state.
1213 66d1f035 René Nussbaumer

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

1220 66d1f035 René Nussbaumer
  """
1221 66d1f035 René Nussbaumer
  if start:
1222 66d1f035 René Nussbaumer
    opcls = opcodes.OpInstanceStartup
1223 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("startup", "started", "starting")
1224 66d1f035 René Nussbaumer
  else:
1225 fcecea0b René Nussbaumer
    opcls = compat.partial(opcodes.OpInstanceShutdown,
1226 3e0ed18c René Nussbaumer
                           timeout=opts.shutdown_timeout,
1227 3e0ed18c René Nussbaumer
                           no_remember=no_remember)
1228 66d1f035 René Nussbaumer
    text_submit, text_success, text_failed = ("shutdown", "stopped", "stopping")
1229 66d1f035 René Nussbaumer
1230 66d1f035 René Nussbaumer
  jex = JobExecutor(opts=opts)
1231 66d1f035 René Nussbaumer
1232 66d1f035 René Nussbaumer
  for inst in inst_list:
1233 66d1f035 René Nussbaumer
    ToStdout("Submit %s of instance %s", text_submit, inst)
1234 66d1f035 René Nussbaumer
    op = opcls(instance_name=inst)
1235 66d1f035 René Nussbaumer
    jex.QueueJob(inst, op)
1236 66d1f035 René Nussbaumer
1237 66d1f035 René Nussbaumer
  results = jex.GetResults()
1238 66d1f035 René Nussbaumer
  bad_cnt = len([1 for (success, _) in results if not success])
1239 66d1f035 René Nussbaumer
1240 66d1f035 René Nussbaumer
  if bad_cnt == 0:
1241 66d1f035 René Nussbaumer
    ToStdout("All instances have been %s successfully", text_success)
1242 66d1f035 René Nussbaumer
  else:
1243 66d1f035 René Nussbaumer
    ToStderr("There were errors while %s instances:\n"
1244 66d1f035 René Nussbaumer
             "%d error(s) out of %d instance(s)", text_failed, bad_cnt,
1245 66d1f035 René Nussbaumer
             len(results))
1246 66d1f035 René Nussbaumer
    return False
1247 66d1f035 René Nussbaumer
1248 66d1f035 René Nussbaumer
  return True
1249 66d1f035 René Nussbaumer
1250 66d1f035 René Nussbaumer
1251 66d1f035 René Nussbaumer
class _RunWhenNodesReachableHelper:
1252 66d1f035 René Nussbaumer
  """Helper class to make shared internal state sharing easier.
1253 66d1f035 René Nussbaumer

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

1256 66d1f035 René Nussbaumer
  """
1257 8e74adce René Nussbaumer
  def __init__(self, node_list, action_cb, node2ip, port, feedback_fn,
1258 66d1f035 René Nussbaumer
               _ping_fn=netutils.TcpPing, _sleep_fn=time.sleep):
1259 66d1f035 René Nussbaumer
    """Init the object.
1260 66d1f035 René Nussbaumer

1261 66d1f035 René Nussbaumer
    @param node_list: The list of nodes to be reachable
1262 66d1f035 René Nussbaumer
    @param action_cb: Callback called when a new host is reachable
1263 66d1f035 René Nussbaumer
    @type node2ip: dict
1264 66d1f035 René Nussbaumer
    @param node2ip: Node to ip mapping
1265 66d1f035 René Nussbaumer
    @param port: The port to use for the TCP ping
1266 8e74adce René Nussbaumer
    @param feedback_fn: The function used for feedback
1267 66d1f035 René Nussbaumer
    @param _ping_fn: Function to check reachabilty (for unittest use only)
1268 66d1f035 René Nussbaumer
    @param _sleep_fn: Function to sleep (for unittest use only)
1269 66d1f035 René Nussbaumer

1270 66d1f035 René Nussbaumer
    """
1271 66d1f035 René Nussbaumer
    self.down = set(node_list)
1272 66d1f035 René Nussbaumer
    self.up = set()
1273 66d1f035 René Nussbaumer
    self.node2ip = node2ip
1274 66d1f035 René Nussbaumer
    self.success = True
1275 66d1f035 René Nussbaumer
    self.action_cb = action_cb
1276 66d1f035 René Nussbaumer
    self.port = port
1277 8e74adce René Nussbaumer
    self.feedback_fn = feedback_fn
1278 66d1f035 René Nussbaumer
    self._ping_fn = _ping_fn
1279 66d1f035 René Nussbaumer
    self._sleep_fn = _sleep_fn
1280 66d1f035 René Nussbaumer
1281 66d1f035 René Nussbaumer
  def __call__(self):
1282 66d1f035 René Nussbaumer
    """When called we run action_cb.
1283 66d1f035 René Nussbaumer

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

1286 66d1f035 René Nussbaumer
    """
1287 66d1f035 René Nussbaumer
    if not self.action_cb(self.up):
1288 66d1f035 René Nussbaumer
      self.success = False
1289 66d1f035 René Nussbaumer
1290 66d1f035 René Nussbaumer
    if self.down:
1291 66d1f035 René Nussbaumer
      raise utils.RetryAgain()
1292 66d1f035 René Nussbaumer
    else:
1293 66d1f035 René Nussbaumer
      return self.success
1294 66d1f035 René Nussbaumer
1295 66d1f035 René Nussbaumer
  def Wait(self, secs):
1296 66d1f035 René Nussbaumer
    """Checks if a host is up or waits remaining seconds.
1297 66d1f035 René Nussbaumer

1298 66d1f035 René Nussbaumer
    @param secs: The secs remaining
1299 66d1f035 René Nussbaumer

1300 66d1f035 René Nussbaumer
    """
1301 66d1f035 René Nussbaumer
    start = time.time()
1302 66d1f035 René Nussbaumer
    for node in self.down:
1303 66d1f035 René Nussbaumer
      if self._ping_fn(self.node2ip[node], self.port, timeout=_EPO_PING_TIMEOUT,
1304 66d1f035 René Nussbaumer
                       live_port_needed=True):
1305 8e74adce René Nussbaumer
        self.feedback_fn("Node %s became available" % node)
1306 66d1f035 René Nussbaumer
        self.up.add(node)
1307 66d1f035 René Nussbaumer
        self.down -= self.up
1308 66d1f035 René Nussbaumer
        # If we have a node available there is the possibility to run the
1309 66d1f035 René Nussbaumer
        # action callback successfully, therefore we don't wait and return
1310 66d1f035 René Nussbaumer
        return
1311 66d1f035 René Nussbaumer
1312 66d1f035 René Nussbaumer
    self._sleep_fn(max(0.0, start + secs - time.time()))
1313 66d1f035 René Nussbaumer
1314 66d1f035 René Nussbaumer
1315 66d1f035 René Nussbaumer
def _RunWhenNodesReachable(node_list, action_cb, interval):
1316 66d1f035 René Nussbaumer
  """Run action_cb when nodes become reachable.
1317 66d1f035 René Nussbaumer

1318 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to be reachable
1319 66d1f035 René Nussbaumer
  @param action_cb: Callback called when a new host is reachable
1320 66d1f035 René Nussbaumer
  @param interval: The earliest time to retry
1321 66d1f035 René Nussbaumer

1322 66d1f035 René Nussbaumer
  """
1323 66d1f035 René Nussbaumer
  client = GetClient()
1324 66d1f035 René Nussbaumer
  cluster_info = client.QueryClusterInfo()
1325 66d1f035 René Nussbaumer
  if cluster_info["primary_ip_version"] == constants.IP4_VERSION:
1326 66d1f035 René Nussbaumer
    family = netutils.IPAddress.family
1327 66d1f035 René Nussbaumer
  else:
1328 66d1f035 René Nussbaumer
    family = netutils.IP6Address.family
1329 66d1f035 René Nussbaumer
1330 66d1f035 René Nussbaumer
  node2ip = dict((node, netutils.GetHostname(node, family=family).ip)
1331 66d1f035 René Nussbaumer
                 for node in node_list)
1332 66d1f035 René Nussbaumer
1333 66d1f035 René Nussbaumer
  port = netutils.GetDaemonPort(constants.NODED)
1334 8e74adce René Nussbaumer
  helper = _RunWhenNodesReachableHelper(node_list, action_cb, node2ip, port,
1335 8e74adce René Nussbaumer
                                        ToStdout)
1336 66d1f035 René Nussbaumer
1337 66d1f035 René Nussbaumer
  try:
1338 66d1f035 René Nussbaumer
    return utils.Retry(helper, interval, _EPO_REACHABLE_TIMEOUT,
1339 66d1f035 René Nussbaumer
                       wait_fn=helper.Wait)
1340 66d1f035 René Nussbaumer
  except utils.RetryTimeout:
1341 66d1f035 René Nussbaumer
    ToStderr("Time exceeded while waiting for nodes to become reachable"
1342 66d1f035 René Nussbaumer
             " again:\n  - %s", "  - ".join(helper.down))
1343 66d1f035 René Nussbaumer
    return False
1344 66d1f035 René Nussbaumer
1345 66d1f035 René Nussbaumer
1346 66d1f035 René Nussbaumer
def _MaybeInstanceStartup(opts, inst_map, nodes_online,
1347 66d1f035 René Nussbaumer
                          _instance_start_fn=_InstanceStart):
1348 66d1f035 René Nussbaumer
  """Start the instances conditional based on node_states.
1349 66d1f035 René Nussbaumer

1350 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1351 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1352 66d1f035 René Nussbaumer
  @param nodes_online: A list of nodes online
1353 66d1f035 René Nussbaumer
  @param _instance_start_fn: Callback to start instances (unittest use only)
1354 66d1f035 René Nussbaumer
  @return: Success of the operation on all instances
1355 66d1f035 René Nussbaumer

1356 66d1f035 René Nussbaumer
  """
1357 66d1f035 René Nussbaumer
  start_inst_list = []
1358 66d1f035 René Nussbaumer
  for (inst, nodes) in inst_map.items():
1359 66d1f035 René Nussbaumer
    if not (nodes - nodes_online):
1360 66d1f035 René Nussbaumer
      # All nodes the instance lives on are back online
1361 66d1f035 René Nussbaumer
      start_inst_list.append(inst)
1362 66d1f035 René Nussbaumer
1363 66d1f035 René Nussbaumer
  for inst in start_inst_list:
1364 66d1f035 René Nussbaumer
    del inst_map[inst]
1365 66d1f035 René Nussbaumer
1366 66d1f035 René Nussbaumer
  if start_inst_list:
1367 66d1f035 René Nussbaumer
    return _instance_start_fn(opts, start_inst_list, True)
1368 66d1f035 René Nussbaumer
1369 66d1f035 René Nussbaumer
  return True
1370 66d1f035 René Nussbaumer
1371 66d1f035 René Nussbaumer
1372 66d1f035 René Nussbaumer
def _EpoOn(opts, full_node_list, node_list, inst_map):
1373 66d1f035 René Nussbaumer
  """Does the actual power on.
1374 66d1f035 René Nussbaumer

1375 66d1f035 René Nussbaumer
  @param opts: The command line options selected by the user
1376 66d1f035 René Nussbaumer
  @param full_node_list: All nodes to operate on (includes nodes not supporting
1377 66d1f035 René Nussbaumer
                         OOB)
1378 66d1f035 René Nussbaumer
  @param node_list: The list of nodes to operate on (all need to support OOB)
1379 66d1f035 René Nussbaumer
  @param inst_map: A dict of inst -> nodes mapping
1380 66d1f035 René Nussbaumer
  @return: The desired exit status
1381 66d1f035 René Nussbaumer

1382 66d1f035 René Nussbaumer
  """
1383 66d1f035 René Nussbaumer
  if node_list and not _OobPower(opts, node_list, False):
1384 66d1f035 René Nussbaumer
    ToStderr("Not all nodes seem to get back up, investigate and start"
1385 66d1f035 René Nussbaumer
             " manually if needed")
1386 66d1f035 René Nussbaumer
1387 66d1f035 René Nussbaumer
  # Wait for the nodes to be back up
1388 66d1f035 René Nussbaumer
  action_cb = compat.partial(_MaybeInstanceStartup, opts, dict(inst_map))
1389 66d1f035 René Nussbaumer
1390 66d1f035 René Nussbaumer
  ToStdout("Waiting until all nodes are available again")
1391 66d1f035 René Nussbaumer
  if not _RunWhenNodesReachable(full_node_list, action_cb, _EPO_PING_INTERVAL):
1392 66d1f035 René Nussbaumer
    ToStderr("Please investigate and start stopped instances manually")
1393 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1394 66d1f035 René Nussbaumer
1395 66d1f035 René Nussbaumer
  return constants.EXIT_SUCCESS
1396 66d1f035 René Nussbaumer
1397 66d1f035 René Nussbaumer
1398 66d1f035 René Nussbaumer
def _EpoOff(opts, node_list, inst_map):
1399 66d1f035 René Nussbaumer
  """Does the actual power off.
1400 66d1f035 René Nussbaumer

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

1406 66d1f035 René Nussbaumer
  """
1407 3e0ed18c René Nussbaumer
  if not _InstanceStart(opts, inst_map.keys(), False, no_remember=True):
1408 66d1f035 René Nussbaumer
    ToStderr("Please investigate and stop instances manually before continuing")
1409 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1410 66d1f035 René Nussbaumer
1411 66d1f035 René Nussbaumer
  if not node_list:
1412 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1413 66d1f035 René Nussbaumer
1414 66d1f035 René Nussbaumer
  if _OobPower(opts, node_list, False):
1415 66d1f035 René Nussbaumer
    return constants.EXIT_SUCCESS
1416 66d1f035 René Nussbaumer
  else:
1417 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1418 66d1f035 René Nussbaumer
1419 66d1f035 René Nussbaumer
1420 1ca7b773 Michael Hanselmann
def Epo(opts, args, cl=None, _on_fn=_EpoOn, _off_fn=_EpoOff,
1421 1ca7b773 Michael Hanselmann
        _confirm_fn=ConfirmOperation,
1422 1ca7b773 Michael Hanselmann
        _stdout_fn=ToStdout, _stderr_fn=ToStderr):
1423 66d1f035 René Nussbaumer
  """EPO operations.
1424 66d1f035 René Nussbaumer

1425 66d1f035 René Nussbaumer
  @param opts: the command line options selected by the user
1426 66d1f035 René Nussbaumer
  @type args: list
1427 66d1f035 René Nussbaumer
  @param args: should contain only one element, the subcommand
1428 66d1f035 René Nussbaumer
  @rtype: int
1429 66d1f035 René Nussbaumer
  @return: the desired exit code
1430 66d1f035 René Nussbaumer

1431 66d1f035 René Nussbaumer
  """
1432 66d1f035 René Nussbaumer
  if opts.groups and opts.show_all:
1433 1ca7b773 Michael Hanselmann
    _stderr_fn("Only one of --groups or --all are allowed")
1434 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1435 66d1f035 René Nussbaumer
  elif args and opts.show_all:
1436 1ca7b773 Michael Hanselmann
    _stderr_fn("Arguments in combination with --all are not allowed")
1437 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1438 66d1f035 René Nussbaumer
1439 1ca7b773 Michael Hanselmann
  if cl is None:
1440 1ca7b773 Michael Hanselmann
    cl = GetClient()
1441 66d1f035 René Nussbaumer
1442 66d1f035 René Nussbaumer
  if opts.groups:
1443 1ca7b773 Michael Hanselmann
    node_query_list = \
1444 1ca7b773 Michael Hanselmann
      itertools.chain(*cl.QueryGroups(args, ["node_list"], False))
1445 66d1f035 René Nussbaumer
  else:
1446 66d1f035 René Nussbaumer
    node_query_list = args
1447 66d1f035 René Nussbaumer
1448 1ca7b773 Michael Hanselmann
  result = cl.QueryNodes(node_query_list, ["name", "master", "pinst_list",
1449 1ca7b773 Michael Hanselmann
                                           "sinst_list", "powered", "offline"],
1450 1ca7b773 Michael Hanselmann
                         False)
1451 45a36f36 Michael Hanselmann
1452 45a36f36 Michael Hanselmann
  all_nodes = map(compat.fst, result)
1453 66d1f035 René Nussbaumer
  node_list = []
1454 66d1f035 René Nussbaumer
  inst_map = {}
1455 3008f56c Iustin Pop
  for (node, master, pinsts, sinsts, powered, offline) in result:
1456 66d1f035 René Nussbaumer
    if not offline:
1457 66d1f035 René Nussbaumer
      for inst in (pinsts + sinsts):
1458 66d1f035 René Nussbaumer
        if inst in inst_map:
1459 66d1f035 René Nussbaumer
          if not master:
1460 66d1f035 René Nussbaumer
            inst_map[inst].add(node)
1461 66d1f035 René Nussbaumer
        elif master:
1462 66d1f035 René Nussbaumer
          inst_map[inst] = set()
1463 66d1f035 René Nussbaumer
        else:
1464 66d1f035 René Nussbaumer
          inst_map[inst] = set([node])
1465 66d1f035 René Nussbaumer
1466 66d1f035 René Nussbaumer
    if master and opts.on:
1467 66d1f035 René Nussbaumer
      # We ignore the master for turning on the machines, in fact we are
1468 66d1f035 René Nussbaumer
      # already operating on the master at this point :)
1469 66d1f035 René Nussbaumer
      continue
1470 66d1f035 René Nussbaumer
    elif master and not opts.show_all:
1471 1ca7b773 Michael Hanselmann
      _stderr_fn("%s is the master node, please do a master-failover to another"
1472 1ca7b773 Michael Hanselmann
                 " node not affected by the EPO or use --all if you intend to"
1473 1ca7b773 Michael Hanselmann
                 " shutdown the whole cluster", node)
1474 66d1f035 René Nussbaumer
      return constants.EXIT_FAILURE
1475 66d1f035 René Nussbaumer
    elif powered is None:
1476 1ca7b773 Michael Hanselmann
      _stdout_fn("Node %s does not support out-of-band handling, it can not be"
1477 1ca7b773 Michael Hanselmann
                 " handled in a fully automated manner", node)
1478 66d1f035 René Nussbaumer
    elif powered == opts.on:
1479 1ca7b773 Michael Hanselmann
      _stdout_fn("Node %s is already in desired power state, skipping", node)
1480 66d1f035 René Nussbaumer
    elif not offline or (offline and powered):
1481 66d1f035 René Nussbaumer
      node_list.append(node)
1482 66d1f035 René Nussbaumer
1483 1ca7b773 Michael Hanselmann
  if not (opts.force or _confirm_fn(all_nodes, "nodes", "epo")):
1484 66d1f035 René Nussbaumer
    return constants.EXIT_FAILURE
1485 66d1f035 René Nussbaumer
1486 66d1f035 René Nussbaumer
  if opts.on:
1487 1ca7b773 Michael Hanselmann
    return _on_fn(opts, all_nodes, node_list, inst_map)
1488 66d1f035 René Nussbaumer
  else:
1489 1ca7b773 Michael Hanselmann
    return _off_fn(opts, node_list, inst_map)
1490 1ca7b773 Michael Hanselmann
1491 66d1f035 René Nussbaumer
1492 ea9d3b40 Bernardo Dal Seno
def _GetCreateCommand(info):
1493 ea9d3b40 Bernardo Dal Seno
  buf = StringIO()
1494 ea9d3b40 Bernardo Dal Seno
  buf.write("gnt-cluster init")
1495 ea9d3b40 Bernardo Dal Seno
  PrintIPolicyCommand(buf, info["ipolicy"], False)
1496 ea9d3b40 Bernardo Dal Seno
  buf.write(" ")
1497 ea9d3b40 Bernardo Dal Seno
  buf.write(info["name"])
1498 ea9d3b40 Bernardo Dal Seno
  return buf.getvalue()
1499 ea9d3b40 Bernardo Dal Seno
1500 ea9d3b40 Bernardo Dal Seno
1501 ea9d3b40 Bernardo Dal Seno
def ShowCreateCommand(opts, args):
1502 ea9d3b40 Bernardo Dal Seno
  """Shows the command that can be used to re-create the cluster.
1503 ea9d3b40 Bernardo Dal Seno

1504 ea9d3b40 Bernardo Dal Seno
  Currently it works only for ipolicy specs.
1505 ea9d3b40 Bernardo Dal Seno

1506 ea9d3b40 Bernardo Dal Seno
  """
1507 ea9d3b40 Bernardo Dal Seno
  cl = GetClient(query=True)
1508 ea9d3b40 Bernardo Dal Seno
  result = cl.QueryClusterInfo()
1509 ea9d3b40 Bernardo Dal Seno
  ToStdout(_GetCreateCommand(result))
1510 ea9d3b40 Bernardo Dal Seno
1511 ea9d3b40 Bernardo Dal Seno
1512 a8083063 Iustin Pop
commands = {
1513 d0c8c01d Iustin Pop
  "init": (
1514 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
1515 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
1516 5a8648eb Andrea Spadaccini
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, MASTER_NETMASK_OPT,
1517 5a8648eb Andrea Spadaccini
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT,
1518 5a8648eb Andrea Spadaccini
     NOMODIFY_SSH_SETUP_OPT, SECONDARY_IP_OPT, VG_NAME_OPT,
1519 5a8648eb Andrea Spadaccini
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, DRBD_HELPER_OPT, NODRBD_STORAGE_OPT,
1520 6204ee71 René Nussbaumer
     DEFAULT_IALLOCATOR_OPT, PRIMARY_IP_VERSION_OPT, PREALLOC_WIPE_DISKS_OPT,
1521 bc5d0215 Andrea Spadaccini
     NODE_PARAMS_OPT, GLOBAL_SHARED_FILEDIR_OPT, USE_EXTERNAL_MIP_SCRIPT,
1522 d2d3935a Bernardo Dal Seno
     DISK_PARAMS_OPT, HV_STATE_OPT, DISK_STATE_OPT, ENABLED_DISK_TEMPLATES_OPT,
1523 919db916 Bernardo Dal Seno
     IPOLICY_STD_SPECS_OPT] + INSTANCE_POLICY_OPTS + SPLIT_ISPECS_OPTS,
1524 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
1525 d0c8c01d Iustin Pop
  "destroy": (
1526 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
1527 6ea815cf Iustin Pop
    "", "Destroy cluster"),
1528 d0c8c01d Iustin Pop
  "rename": (
1529 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
1530 db5a8a2d Iustin Pop
    [FORCE_OPT, DRY_RUN_OPT],
1531 6ea815cf Iustin Pop
    "<new_name>",
1532 6ea815cf Iustin Pop
    "Renames the cluster"),
1533 d0c8c01d Iustin Pop
  "redist-conf": (
1534 aa06f8c6 Michael Hanselmann
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT, DRY_RUN_OPT, PRIORITY_OPT],
1535 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
1536 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
1537 d0c8c01d Iustin Pop
  "verify": (
1538 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
1539 db5a8a2d Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT,
1540 93f2399e Andrea Spadaccini
     DRY_RUN_OPT, PRIORITY_OPT, NODEGROUP_OPT, IGNORE_ERRORS_OPT],
1541 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
1542 d0c8c01d Iustin Pop
  "verify-disks": (
1543 aa06f8c6 Michael Hanselmann
    VerifyDisks, ARGS_NONE, [PRIORITY_OPT],
1544 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
1545 d0c8c01d Iustin Pop
  "repair-disk-sizes": (
1546 aa06f8c6 Michael Hanselmann
    RepairDiskSizes, ARGS_MANY_INSTANCES, [DRY_RUN_OPT, PRIORITY_OPT],
1547 eb5ac108 Michael Hanselmann
    "[instance...]", "Updates mismatches in recorded disk sizes"),
1548 d0c8c01d Iustin Pop
  "master-failover": (
1549 6022a419 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT, FORCE_FAILOVER],
1550 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
1551 d0c8c01d Iustin Pop
  "master-ping": (
1552 4404ffad Iustin Pop
    MasterPing, ARGS_NONE, [],
1553 4404ffad Iustin Pop
    "", "Checks if the master is alive"),
1554 d0c8c01d Iustin Pop
  "version": (
1555 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
1556 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
1557 d0c8c01d Iustin Pop
  "getmaster": (
1558 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
1559 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
1560 d0c8c01d Iustin Pop
  "copyfile": (
1561 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
1562 b6e88032 Michael Hanselmann
    [NODE_LIST_OPT, USE_REPL_NET_OPT, NODEGROUP_OPT],
1563 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
1564 d0c8c01d Iustin Pop
  "command": (
1565 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
1566 d5b031dc Michael Hanselmann
    [NODE_LIST_OPT, NODEGROUP_OPT, SHOW_MACHINE_OPT, FAILURE_ONLY_OPT],
1567 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
1568 d0c8c01d Iustin Pop
  "info": (
1569 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
1570 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
1571 d0c8c01d Iustin Pop
  "list-tags": (
1572 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
1573 d0c8c01d Iustin Pop
  "add-tags": (
1574 6bc3ed14 Michael Hanselmann
    AddTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1575 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
1576 d0c8c01d Iustin Pop
  "remove-tags": (
1577 6bc3ed14 Michael Hanselmann
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1578 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
1579 d0c8c01d Iustin Pop
  "search-tags": (
1580 aa06f8c6 Michael Hanselmann
    SearchTags, [ArgUnknown(min=1, max=1)], [PRIORITY_OPT], "",
1581 aa06f8c6 Michael Hanselmann
    "Searches the tags on all objects on"
1582 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
1583 d0c8c01d Iustin Pop
  "queue": (
1584 6ea815cf Iustin Pop
    QueueOps,
1585 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
1586 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
1587 d0c8c01d Iustin Pop
  "watcher": (
1588 6ea815cf Iustin Pop
    WatcherOps,
1589 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
1590 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
1591 064c21f8 Iustin Pop
    [],
1592 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
1593 d0c8c01d Iustin Pop
  "modify": (
1594 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
1595 2f836021 Klaus Aehlig
    [FORCE_OPT,
1596 2f836021 Klaus Aehlig
     BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT, MASTER_NETDEV_OPT,
1597 5a8648eb Andrea Spadaccini
     MASTER_NETMASK_OPT, NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT,
1598 5a8648eb Andrea Spadaccini
     MAINTAIN_NODE_HEALTH_OPT, UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT,
1599 5a8648eb Andrea Spadaccini
     DRBD_HELPER_OPT, NODRBD_STORAGE_OPT, DEFAULT_IALLOCATOR_OPT,
1600 5a8648eb Andrea Spadaccini
     RESERVED_LVS_OPT, DRY_RUN_OPT, PRIORITY_OPT, PREALLOC_WIPE_DISKS_OPT,
1601 2da9f556 René Nussbaumer
     NODE_PARAMS_OPT, USE_EXTERNAL_MIP_SCRIPT, DISK_PARAMS_OPT, HV_STATE_OPT,
1602 d2d3935a Bernardo Dal Seno
     DISK_STATE_OPT, SUBMIT_OPT, ENABLED_DISK_TEMPLATES_OPT,
1603 75f2ff7d Michele Tartara
     IPOLICY_STD_SPECS_OPT, MODIFY_ETCHOSTS_OPT] + INSTANCE_POLICY_OPTS,
1604 6ea815cf Iustin Pop
    "[opts...]",
1605 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
1606 6d4a1656 Michael Hanselmann
  "renew-crypto": (
1607 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
1608 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
1609 3db3eb2a Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT,
1610 b6267745 Andrea Spadaccini
     NEW_CLUSTER_DOMAIN_SECRET_OPT, CLUSTER_DOMAIN_SECRET_OPT,
1611 b6267745 Andrea Spadaccini
     NEW_SPICE_CERT_OPT, SPICE_CERT_OPT, SPICE_CACERT_OPT],
1612 6d4a1656 Michael Hanselmann
    "[opts...]",
1613 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
1614 66d1f035 René Nussbaumer
  "epo": (
1615 66d1f035 René Nussbaumer
    Epo, [ArgUnknown()],
1616 fcecea0b René Nussbaumer
    [FORCE_OPT, ON_OPT, GROUPS_OPT, ALL_OPT, OOB_TIMEOUT_OPT,
1617 cfed3b9f René Nussbaumer
     SHUTDOWN_TIMEOUT_OPT, POWER_DELAY_OPT],
1618 66d1f035 René Nussbaumer
    "[opts...] [args]",
1619 66d1f035 René Nussbaumer
    "Performs an emergency power-off on given args"),
1620 fb926117 Andrea Spadaccini
  "activate-master-ip": (
1621 fb926117 Andrea Spadaccini
    ActivateMasterIp, ARGS_NONE, [], "", "Activates the master IP"),
1622 fb926117 Andrea Spadaccini
  "deactivate-master-ip": (
1623 fb926117 Andrea Spadaccini
    DeactivateMasterIp, ARGS_NONE, [CONFIRM_OPT], "",
1624 fb926117 Andrea Spadaccini
    "Deactivates the master IP"),
1625 ea9d3b40 Bernardo Dal Seno
  "show-ispecs-cmd": (
1626 ea9d3b40 Bernardo Dal Seno
    ShowCreateCommand, ARGS_NONE, [], "",
1627 ea9d3b40 Bernardo Dal Seno
    "Show the command line to re-create the cluster"),
1628 a8083063 Iustin Pop
  }
1629 a8083063 Iustin Pop
1630 6d4a1656 Michael Hanselmann
1631 c28502b1 Iustin Pop
#: dictionary with aliases for commands
1632 c28502b1 Iustin Pop
aliases = {
1633 d0c8c01d Iustin Pop
  "masterfailover": "master-failover",
1634 96897af7 Alexander Schreiber
  "show": "info",
1635 c28502b1 Iustin Pop
}
1636 c28502b1 Iustin Pop
1637 c28502b1 Iustin Pop
1638 7b3e7d41 Michael Hanselmann
def Main():
1639 7b3e7d41 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER},
1640 7b3e7d41 Michael Hanselmann
                     aliases=aliases)