Statistics
| Branch: | Tag: | Revision:

root / scripts / gnt-cluster @ d729e03a

History | View | Annotate | Download (25.5 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 2d54e29c Iustin Pop
# pylint: disable-msg=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 a8083063 Iustin Pop
import sys
30 b3989551 Iustin Pop
import os.path
31 95b2e626 Michael Hanselmann
import time
32 6d4a1656 Michael Hanselmann
import OpenSSL
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti.cli import *
35 a8083063 Iustin Pop
from ganeti import opcodes
36 c2a62a33 Michael Hanselmann
from ganeti import constants
37 f4d4e184 Iustin Pop
from ganeti import errors
38 b63ed789 Iustin Pop
from ganeti import utils
39 a0c9f010 Michael Hanselmann
from ganeti import bootstrap
40 b3989551 Iustin Pop
from ganeti import ssh
41 d3cfe525 Guido Trotter
from ganeti import objects
42 1338f2b4 Balazs Lecz
from ganeti import uidpool
43 cea881e5 Michael Hanselmann
from ganeti import compat
44 a8083063 Iustin Pop
45 a8083063 Iustin Pop
46 4331f6cd Michael Hanselmann
@UsesRPC
47 a8083063 Iustin Pop
def InitCluster(opts, args):
48 a8083063 Iustin Pop
  """Initialize the cluster.
49 a8083063 Iustin Pop
50 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
51 469ee405 Iustin Pop
  @type args: list
52 469ee405 Iustin Pop
  @param args: should contain only one element, the desired
53 469ee405 Iustin Pop
      cluster name
54 469ee405 Iustin Pop
  @rtype: int
55 469ee405 Iustin Pop
  @return: the desired exit code
56 a8083063 Iustin Pop
57 a8083063 Iustin Pop
  """
58 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
59 3a24c527 Iustin Pop
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
60 90b6aa3a Manuel Franceschini
    return 1
61 90b6aa3a Manuel Franceschini
62 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
63 90b6aa3a Manuel Franceschini
  if opts.lvm_storage and not opts.vg_name:
64 90b6aa3a Manuel Franceschini
    vg_name = constants.DEFAULT_VG
65 90b6aa3a Manuel Franceschini
66 ea3a925f Alexander Schreiber
  hvlist = opts.enabled_hypervisors
67 383a3591 Iustin Pop
  if hvlist is None:
68 383a3591 Iustin Pop
    hvlist = constants.DEFAULT_ENABLED_HYPERVISOR
69 066f465d Guido Trotter
  hvlist = hvlist.split(",")
70 ea3a925f Alexander Schreiber
71 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
72 ea3a925f Alexander Schreiber
  beparams = opts.beparams
73 b6a30b0d Guido Trotter
  nicparams = opts.nicparams
74 ea3a925f Alexander Schreiber
75 ea3a925f Alexander Schreiber
  # prepare beparams dict
76 d3cfe525 Guido Trotter
  beparams = objects.FillDict(constants.BEC_DEFAULTS, beparams)
77 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
78 ea3a925f Alexander Schreiber
79 b6a30b0d Guido Trotter
  # prepare nicparams dict
80 b6a30b0d Guido Trotter
  nicparams = objects.FillDict(constants.NICC_DEFAULTS, nicparams)
81 b6a30b0d Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
82 b6a30b0d Guido Trotter
83 ea3a925f Alexander Schreiber
  # prepare hvparams dict
84 ea3a925f Alexander Schreiber
  for hv in constants.HYPER_TYPES:
85 ea3a925f Alexander Schreiber
    if hv not in hvparams:
86 ea3a925f Alexander Schreiber
      hvparams[hv] = {}
87 d3cfe525 Guido Trotter
    hvparams[hv] = objects.FillDict(constants.HVC_DEFAULTS[hv], hvparams[hv])
88 a5728081 Guido Trotter
    utils.ForceDictType(hvparams[hv], constants.HVS_PARAMETER_TYPES)
89 ea3a925f Alexander Schreiber
90 e32df528 Iustin Pop
  if opts.candidate_pool_size is None:
91 e32df528 Iustin Pop
    opts.candidate_pool_size = constants.MASTER_POOL_SIZE_DEFAULT
92 e32df528 Iustin Pop
93 e3646f22 Iustin Pop
  if opts.mac_prefix is None:
94 e3646f22 Iustin Pop
    opts.mac_prefix = constants.DEFAULT_MAC_PREFIX
95 e3646f22 Iustin Pop
96 39b0f0c2 Balazs Lecz
  uid_pool = opts.uid_pool
97 39b0f0c2 Balazs Lecz
  if uid_pool is not None:
98 39b0f0c2 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
99 39b0f0c2 Balazs Lecz
100 a0c9f010 Michael Hanselmann
  bootstrap.InitCluster(cluster_name=args[0],
101 a0c9f010 Michael Hanselmann
                        secondary_ip=opts.secondary_ip,
102 a0c9f010 Michael Hanselmann
                        vg_name=vg_name,
103 a0c9f010 Michael Hanselmann
                        mac_prefix=opts.mac_prefix,
104 a0c9f010 Michael Hanselmann
                        master_netdev=opts.master_netdev,
105 ea3a925f Alexander Schreiber
                        file_storage_dir=opts.file_storage_dir,
106 ea3a925f Alexander Schreiber
                        enabled_hypervisors=hvlist,
107 ea3a925f Alexander Schreiber
                        hvparams=hvparams,
108 ce735215 Guido Trotter
                        beparams=beparams,
109 b6a30b0d Guido Trotter
                        nicparams=nicparams,
110 ce735215 Guido Trotter
                        candidate_pool_size=opts.candidate_pool_size,
111 b86a6bcd Guido Trotter
                        modify_etc_hosts=opts.modify_etc_hosts,
112 b989b9d9 Ken Wehr
                        modify_ssh_setup=opts.modify_ssh_setup,
113 3953242f Iustin Pop
                        maintain_node_health=opts.maintain_node_health,
114 39b0f0c2 Balazs Lecz
                        uid_pool=uid_pool,
115 ce735215 Guido Trotter
                        )
116 3552cd2e Luca Bigliardi
  op = opcodes.OpPostInitCluster()
117 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
118 a8083063 Iustin Pop
  return 0
119 a8083063 Iustin Pop
120 a8083063 Iustin Pop
121 4331f6cd Michael Hanselmann
@UsesRPC
122 a8083063 Iustin Pop
def DestroyCluster(opts, args):
123 a8083063 Iustin Pop
  """Destroy the cluster.
124 a8083063 Iustin Pop
125 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
126 469ee405 Iustin Pop
  @type args: list
127 469ee405 Iustin Pop
  @param args: should be an empty list
128 469ee405 Iustin Pop
  @rtype: int
129 469ee405 Iustin Pop
  @return: the desired exit code
130 098c0958 Michael Hanselmann
131 a8083063 Iustin Pop
  """
132 a8083063 Iustin Pop
  if not opts.yes_do_it:
133 3a24c527 Iustin Pop
    ToStderr("Destroying a cluster is irreversible. If you really want"
134 3a24c527 Iustin Pop
             " destroy this cluster, supply the --yes-do-it option.")
135 a8083063 Iustin Pop
    return 1
136 a8083063 Iustin Pop
137 a8083063 Iustin Pop
  op = opcodes.OpDestroyCluster()
138 400ca2f7 Iustin Pop
  master = SubmitOpCode(op, opts=opts)
139 140aa4a8 Iustin Pop
  # if we reached this, the opcode didn't fail; we can proceed to
140 140aa4a8 Iustin Pop
  # shutdown all the daemons
141 140aa4a8 Iustin Pop
  bootstrap.FinalizeClusterDestroy(master)
142 a8083063 Iustin Pop
  return 0
143 a8083063 Iustin Pop
144 a8083063 Iustin Pop
145 07bd8a51 Iustin Pop
def RenameCluster(opts, args):
146 07bd8a51 Iustin Pop
  """Rename the cluster.
147 07bd8a51 Iustin Pop
148 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
149 469ee405 Iustin Pop
  @type args: list
150 469ee405 Iustin Pop
  @param args: should contain only one element, the new cluster name
151 469ee405 Iustin Pop
  @rtype: int
152 469ee405 Iustin Pop
  @return: the desired exit code
153 07bd8a51 Iustin Pop
154 07bd8a51 Iustin Pop
  """
155 07bd8a51 Iustin Pop
  name = args[0]
156 07bd8a51 Iustin Pop
  if not opts.force:
157 07bd8a51 Iustin Pop
    usertext = ("This will rename the cluster to '%s'. If you are connected"
158 07bd8a51 Iustin Pop
                " over the network to the cluster name, the operation is very"
159 07bd8a51 Iustin Pop
                " dangerous as the IP address will be removed from the node"
160 07bd8a51 Iustin Pop
                " and the change may not go through. Continue?") % name
161 47988778 Iustin Pop
    if not AskUser(usertext):
162 07bd8a51 Iustin Pop
      return 1
163 07bd8a51 Iustin Pop
164 07bd8a51 Iustin Pop
  op = opcodes.OpRenameCluster(name=name)
165 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
166 07bd8a51 Iustin Pop
  return 0
167 07bd8a51 Iustin Pop
168 07bd8a51 Iustin Pop
169 afee0879 Iustin Pop
def RedistributeConfig(opts, args):
170 afee0879 Iustin Pop
  """Forces push of the cluster configuration.
171 afee0879 Iustin Pop
172 afee0879 Iustin Pop
  @param opts: the command line options selected by the user
173 afee0879 Iustin Pop
  @type args: list
174 afee0879 Iustin Pop
  @param args: empty list
175 afee0879 Iustin Pop
  @rtype: int
176 afee0879 Iustin Pop
  @return: the desired exit code
177 afee0879 Iustin Pop
178 afee0879 Iustin Pop
  """
179 81a49123 Iustin Pop
  op = opcodes.OpRedistributeConfig()
180 afee0879 Iustin Pop
  SubmitOrSend(op, opts)
181 afee0879 Iustin Pop
  return 0
182 afee0879 Iustin Pop
183 afee0879 Iustin Pop
184 a8083063 Iustin Pop
def ShowClusterVersion(opts, args):
185 a8083063 Iustin Pop
  """Write version of ganeti software to the standard output.
186 a8083063 Iustin Pop
187 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
188 469ee405 Iustin Pop
  @type args: list
189 469ee405 Iustin Pop
  @param args: should be an empty list
190 469ee405 Iustin Pop
  @rtype: int
191 469ee405 Iustin Pop
  @return: the desired exit code
192 a8083063 Iustin Pop
193 a8083063 Iustin Pop
  """
194 2e7b8369 Iustin Pop
  cl = GetClient()
195 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
196 3a24c527 Iustin Pop
  ToStdout("Software version: %s", result["software_version"])
197 3a24c527 Iustin Pop
  ToStdout("Internode protocol: %s", result["protocol_version"])
198 3a24c527 Iustin Pop
  ToStdout("Configuration format: %s", result["config_version"])
199 3a24c527 Iustin Pop
  ToStdout("OS api version: %s", result["os_api_version"])
200 3a24c527 Iustin Pop
  ToStdout("Export interface: %s", result["export_version"])
201 a8083063 Iustin Pop
  return 0
202 a8083063 Iustin Pop
203 a8083063 Iustin Pop
204 a8083063 Iustin Pop
def ShowClusterMaster(opts, args):
205 a8083063 Iustin Pop
  """Write name of master node to the standard output.
206 a8083063 Iustin Pop
207 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
208 469ee405 Iustin Pop
  @type args: list
209 469ee405 Iustin Pop
  @param args: should be an empty list
210 469ee405 Iustin Pop
  @rtype: int
211 469ee405 Iustin Pop
  @return: the desired exit code
212 a8083063 Iustin Pop
213 a8083063 Iustin Pop
  """
214 8eb148ae Iustin Pop
  master = bootstrap.GetMaster()
215 8eb148ae Iustin Pop
  ToStdout(master)
216 a8083063 Iustin Pop
  return 0
217 a8083063 Iustin Pop
218 cac599f1 Michael Hanselmann
219 d729e03a Guido Trotter
def _PrintGroupedParams(paramsdict, level=1, roman=False):
220 1094acda Guido Trotter
  """Print Grouped parameters (be, nic, disk) by group.
221 1094acda Guido Trotter
222 1094acda Guido Trotter
  @type paramsdict: dict of dicts
223 1094acda Guido Trotter
  @param paramsdict: {group: {param: value, ...}, ...}
224 664a9d73 René Nussbaumer
  @type level: int
225 664a9d73 René Nussbaumer
  @param level: Level of indention
226 1094acda Guido Trotter
227 1094acda Guido Trotter
  """
228 664a9d73 René Nussbaumer
  indent = "  " * level
229 9d91c6ab Guido Trotter
  for item, val in sorted(paramsdict.items()):
230 664a9d73 René Nussbaumer
    if isinstance(val, dict):
231 664a9d73 René Nussbaumer
      ToStdout("%s- %s:", indent, item)
232 d729e03a Guido Trotter
      _PrintGroupedParams(val, level=level + 1, roman=roman)
233 d729e03a Guido Trotter
    elif roman and isinstance(val, int):
234 d729e03a Guido Trotter
      ToStdout("%s  %s: %s", indent, item, compat.TryToRoman(val))
235 664a9d73 René Nussbaumer
    else:
236 664a9d73 René Nussbaumer
      ToStdout("%s  %s: %s", indent, item, val)
237 a8083063 Iustin Pop
238 cac599f1 Michael Hanselmann
239 a8083063 Iustin Pop
def ShowClusterConfig(opts, args):
240 a8083063 Iustin Pop
  """Shows cluster information.
241 a8083063 Iustin Pop
242 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
243 469ee405 Iustin Pop
  @type args: list
244 469ee405 Iustin Pop
  @param args: should be an empty list
245 469ee405 Iustin Pop
  @rtype: int
246 469ee405 Iustin Pop
  @return: the desired exit code
247 469ee405 Iustin Pop
248 a8083063 Iustin Pop
  """
249 2e7b8369 Iustin Pop
  cl = GetClient()
250 2e7b8369 Iustin Pop
  result = cl.QueryClusterInfo()
251 a8083063 Iustin Pop
252 3a24c527 Iustin Pop
  ToStdout("Cluster name: %s", result["name"])
253 259578eb Iustin Pop
  ToStdout("Cluster UUID: %s", result["uuid"])
254 a8083063 Iustin Pop
255 90f72445 Iustin Pop
  ToStdout("Creation time: %s", utils.FormatTime(result["ctime"]))
256 90f72445 Iustin Pop
  ToStdout("Modification time: %s", utils.FormatTime(result["mtime"]))
257 90f72445 Iustin Pop
258 3a24c527 Iustin Pop
  ToStdout("Master node: %s", result["master"])
259 a8083063 Iustin Pop
260 3a24c527 Iustin Pop
  ToStdout("Architecture (this node): %s (%s)",
261 3a24c527 Iustin Pop
           result["architecture"][0], result["architecture"][1])
262 a8083063 Iustin Pop
263 c118d1f4 Michael Hanselmann
  if result["tags"]:
264 1f864b60 Iustin Pop
    tags = utils.CommaJoin(utils.NiceSort(result["tags"]))
265 c118d1f4 Michael Hanselmann
  else:
266 c118d1f4 Michael Hanselmann
    tags = "(none)"
267 c118d1f4 Michael Hanselmann
268 c118d1f4 Michael Hanselmann
  ToStdout("Tags: %s", tags)
269 c118d1f4 Michael Hanselmann
270 02691904 Alexander Schreiber
  ToStdout("Default hypervisor: %s", result["default_hypervisor"])
271 1f864b60 Iustin Pop
  ToStdout("Enabled hypervisors: %s",
272 1f864b60 Iustin Pop
           utils.CommaJoin(result["enabled_hypervisors"]))
273 469f88e1 Iustin Pop
274 3a24c527 Iustin Pop
  ToStdout("Hypervisor parameters:")
275 1094acda Guido Trotter
  _PrintGroupedParams(result["hvparams"])
276 469f88e1 Iustin Pop
277 664a9d73 René Nussbaumer
  ToStdout("OS specific hypervisor parameters:")
278 664a9d73 René Nussbaumer
  _PrintGroupedParams(result["os_hvp"])
279 664a9d73 René Nussbaumer
280 3a24c527 Iustin Pop
  ToStdout("Cluster parameters:")
281 d729e03a Guido Trotter
  ToStdout("  - candidate pool size: %s",
282 d729e03a Guido Trotter
            compat.TryToRoman(result["candidate_pool_size"],
283 d729e03a Guido Trotter
                              convert=opts.roman_integers))
284 a8001106 Guido Trotter
  ToStdout("  - master netdev: %s", result["master_netdev"])
285 a8001106 Guido Trotter
  ToStdout("  - lvm volume group: %s", result["volume_group_name"])
286 a8001106 Guido Trotter
  ToStdout("  - file storage path: %s", result["file_storage_dir"])
287 3953242f Iustin Pop
  ToStdout("  - maintenance of node health: %s",
288 3953242f Iustin Pop
           result["maintain_node_health"])
289 d729e03a Guido Trotter
  ToStdout("  - uid pool: %s",
290 d729e03a Guido Trotter
            uidpool.FormatUidPool(result["uid_pool"],
291 d729e03a Guido Trotter
                                  roman=opts.roman_integers))
292 4b7735f9 Iustin Pop
293 4b7735f9 Iustin Pop
  ToStdout("Default instance parameters:")
294 d729e03a Guido Trotter
  _PrintGroupedParams(result["beparams"], roman=opts.roman_integers)
295 1094acda Guido Trotter
296 1094acda Guido Trotter
  ToStdout("Default nic parameters:")
297 d729e03a Guido Trotter
  _PrintGroupedParams(result["nicparams"], roman=opts.roman_integers)
298 8a12ce45 Iustin Pop
299 a8083063 Iustin Pop
  return 0
300 a8083063 Iustin Pop
301 a8083063 Iustin Pop
302 a8083063 Iustin Pop
def ClusterCopyFile(opts, args):
303 a8083063 Iustin Pop
  """Copy a file from master to some nodes.
304 a8083063 Iustin Pop
305 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
306 469ee405 Iustin Pop
  @type args: list
307 469ee405 Iustin Pop
  @param args: should contain only one element, the path of
308 469ee405 Iustin Pop
      the file to be copied
309 469ee405 Iustin Pop
  @rtype: int
310 469ee405 Iustin Pop
  @return: the desired exit code
311 a8083063 Iustin Pop
312 a8083063 Iustin Pop
  """
313 b3989551 Iustin Pop
  filename = args[0]
314 b3989551 Iustin Pop
  if not os.path.exists(filename):
315 debac808 Iustin Pop
    raise errors.OpPrereqError("No such filename '%s'" % filename,
316 debac808 Iustin Pop
                               errors.ECODE_INVAL)
317 b3989551 Iustin Pop
318 56bece1f Iustin Pop
  cl = GetClient()
319 56bece1f Iustin Pop
320 56bece1f Iustin Pop
  cluster_name = cl.QueryConfigValues(["cluster_name"])[0]
321 56bece1f Iustin Pop
322 74adc100 Iustin Pop
  results = GetOnlineNodes(nodes=opts.nodes, cl=cl, filter_master=True,
323 74adc100 Iustin Pop
                           secondary_ips=opts.use_replication_network)
324 e00ea635 Michael Hanselmann
325 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
326 b3989551 Iustin Pop
  for node in results:
327 b3989551 Iustin Pop
    if not srun.CopyFileToNode(node, filename):
328 3a24c527 Iustin Pop
      ToStderr("Copy of file %s to node %s failed", filename, node)
329 b3989551 Iustin Pop
330 a8083063 Iustin Pop
  return 0
331 a8083063 Iustin Pop
332 a8083063 Iustin Pop
333 a8083063 Iustin Pop
def RunClusterCommand(opts, args):
334 a8083063 Iustin Pop
  """Run a command on some nodes.
335 a8083063 Iustin Pop
336 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
337 469ee405 Iustin Pop
  @type args: list
338 469ee405 Iustin Pop
  @param args: should contain the command to be run and its arguments
339 469ee405 Iustin Pop
  @rtype: int
340 469ee405 Iustin Pop
  @return: the desired exit code
341 a8083063 Iustin Pop
342 a8083063 Iustin Pop
  """
343 56bece1f Iustin Pop
  cl = GetClient()
344 7688d0d3 Michael Hanselmann
345 a8083063 Iustin Pop
  command = " ".join(args)
346 4040a784 Iustin Pop
347 4040a784 Iustin Pop
  nodes = GetOnlineNodes(nodes=opts.nodes, cl=cl)
348 56bece1f Iustin Pop
349 56bece1f Iustin Pop
  cluster_name, master_node = cl.QueryConfigValues(["cluster_name",
350 56bece1f Iustin Pop
                                                    "master_node"])
351 b3989551 Iustin Pop
352 56bece1f Iustin Pop
  srun = ssh.SshRunner(cluster_name=cluster_name)
353 b3989551 Iustin Pop
354 7688d0d3 Michael Hanselmann
  # Make sure master node is at list end
355 b3989551 Iustin Pop
  if master_node in nodes:
356 b3989551 Iustin Pop
    nodes.remove(master_node)
357 b3989551 Iustin Pop
    nodes.append(master_node)
358 b3989551 Iustin Pop
359 b3989551 Iustin Pop
  for name in nodes:
360 b3989551 Iustin Pop
    result = srun.Run(name, "root", command)
361 3a24c527 Iustin Pop
    ToStdout("------------------------------------------------")
362 3a24c527 Iustin Pop
    ToStdout("node: %s", name)
363 3a24c527 Iustin Pop
    ToStdout("%s", result.output)
364 3a24c527 Iustin Pop
    ToStdout("return code = %s", result.exit_code)
365 b3989551 Iustin Pop
366 b3989551 Iustin Pop
  return 0
367 a8083063 Iustin Pop
368 a8083063 Iustin Pop
369 a8083063 Iustin Pop
def VerifyCluster(opts, args):
370 a8083063 Iustin Pop
  """Verify integrity of cluster, performing various test on nodes.
371 a8083063 Iustin Pop
372 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
373 469ee405 Iustin Pop
  @type args: list
374 469ee405 Iustin Pop
  @param args: should be an empty list
375 469ee405 Iustin Pop
  @rtype: int
376 469ee405 Iustin Pop
  @return: the desired exit code
377 a8083063 Iustin Pop
378 a8083063 Iustin Pop
  """
379 8d59409f Iustin Pop
  skip_checks = []
380 e54c4c5e Guido Trotter
  if opts.skip_nplusone_mem:
381 e54c4c5e Guido Trotter
    skip_checks.append(constants.VERIFY_NPLUSONE_MEM)
382 7c874ee1 Iustin Pop
  op = opcodes.OpVerifyCluster(skip_checks=skip_checks,
383 7c874ee1 Iustin Pop
                               verbose=opts.verbose,
384 a0c9776a Iustin Pop
                               error_codes=opts.error_codes,
385 a0c9776a Iustin Pop
                               debug_simulate_errors=opts.simulate_errors)
386 400ca2f7 Iustin Pop
  if SubmitOpCode(op, opts=opts):
387 34290825 Michael Hanselmann
    return 0
388 34290825 Michael Hanselmann
  else:
389 34290825 Michael Hanselmann
    return 1
390 a8083063 Iustin Pop
391 a8083063 Iustin Pop
392 f4d4e184 Iustin Pop
def VerifyDisks(opts, args):
393 f4d4e184 Iustin Pop
  """Verify integrity of cluster disks.
394 f4d4e184 Iustin Pop
395 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
396 469ee405 Iustin Pop
  @type args: list
397 469ee405 Iustin Pop
  @param args: should be an empty list
398 469ee405 Iustin Pop
  @rtype: int
399 469ee405 Iustin Pop
  @return: the desired exit code
400 f4d4e184 Iustin Pop
401 f4d4e184 Iustin Pop
  """
402 f4d4e184 Iustin Pop
  op = opcodes.OpVerifyDisks()
403 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
404 29d376ec Iustin Pop
  if not isinstance(result, (list, tuple)) or len(result) != 3:
405 f4d4e184 Iustin Pop
    raise errors.ProgrammerError("Unknown result type for OpVerifyDisks")
406 f4d4e184 Iustin Pop
407 29d376ec Iustin Pop
  bad_nodes, instances, missing = result
408 b63ed789 Iustin Pop
409 f4d4e184 Iustin Pop
  retcode = constants.EXIT_SUCCESS
410 b63ed789 Iustin Pop
411 29d376ec Iustin Pop
  if bad_nodes:
412 29d376ec Iustin Pop
    for node, text in bad_nodes.items():
413 29d376ec Iustin Pop
      ToStdout("Error gathering data on node %s: %s",
414 26f15862 Iustin Pop
               node, utils.SafeEncode(text[-400:]))
415 b63ed789 Iustin Pop
      retcode |= 1
416 3a24c527 Iustin Pop
      ToStdout("You need to fix these nodes first before fixing instances")
417 b63ed789 Iustin Pop
418 f4d4e184 Iustin Pop
  if instances:
419 f4d4e184 Iustin Pop
    for iname in instances:
420 b63ed789 Iustin Pop
      if iname in missing:
421 b63ed789 Iustin Pop
        continue
422 f4d4e184 Iustin Pop
      op = opcodes.OpActivateInstanceDisks(instance_name=iname)
423 f4d4e184 Iustin Pop
      try:
424 3a24c527 Iustin Pop
        ToStdout("Activating disks for instance '%s'", iname)
425 400ca2f7 Iustin Pop
        SubmitOpCode(op, opts=opts)
426 f4d4e184 Iustin Pop
      except errors.GenericError, err:
427 f4d4e184 Iustin Pop
        nret, msg = FormatError(err)
428 f4d4e184 Iustin Pop
        retcode |= nret
429 3a24c527 Iustin Pop
        ToStderr("Error activating disks for instance %s: %s", iname, msg)
430 b63ed789 Iustin Pop
431 b63ed789 Iustin Pop
  if missing:
432 b63ed789 Iustin Pop
    for iname, ival in missing.iteritems():
433 cea881e5 Michael Hanselmann
      all_missing = compat.all(ival, lambda x: x[0] in bad_nodes)
434 b63ed789 Iustin Pop
      if all_missing:
435 3a24c527 Iustin Pop
        ToStdout("Instance %s cannot be verified as it lives on"
436 3a24c527 Iustin Pop
                 " broken nodes", iname)
437 b63ed789 Iustin Pop
      else:
438 3a24c527 Iustin Pop
        ToStdout("Instance %s has missing logical volumes:", iname)
439 b63ed789 Iustin Pop
        ival.sort()
440 b63ed789 Iustin Pop
        for node, vol in ival:
441 29d376ec Iustin Pop
          if node in bad_nodes:
442 3a24c527 Iustin Pop
            ToStdout("\tbroken node %s /dev/xenvg/%s", node, vol)
443 b63ed789 Iustin Pop
          else:
444 3a24c527 Iustin Pop
            ToStdout("\t%s /dev/xenvg/%s", node, vol)
445 3a24c527 Iustin Pop
    ToStdout("You need to run replace_disks for all the above"
446 b63ed789 Iustin Pop
           " instances, if this message persist after fixing nodes.")
447 b63ed789 Iustin Pop
    retcode |= 1
448 f4d4e184 Iustin Pop
449 f4d4e184 Iustin Pop
  return retcode
450 f4d4e184 Iustin Pop
451 f4d4e184 Iustin Pop
452 60975797 Iustin Pop
def RepairDiskSizes(opts, args):
453 60975797 Iustin Pop
  """Verify sizes of cluster disks.
454 60975797 Iustin Pop
455 60975797 Iustin Pop
  @param opts: the command line options selected by the user
456 60975797 Iustin Pop
  @type args: list
457 60975797 Iustin Pop
  @param args: optional list of instances to restrict check to
458 60975797 Iustin Pop
  @rtype: int
459 60975797 Iustin Pop
  @return: the desired exit code
460 60975797 Iustin Pop
461 60975797 Iustin Pop
  """
462 60975797 Iustin Pop
  op = opcodes.OpRepairDiskSizes(instances=args)
463 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
464 60975797 Iustin Pop
465 60975797 Iustin Pop
466 4331f6cd Michael Hanselmann
@UsesRPC
467 a8083063 Iustin Pop
def MasterFailover(opts, args):
468 a8083063 Iustin Pop
  """Failover the master node.
469 a8083063 Iustin Pop
470 a8083063 Iustin Pop
  This command, when run on a non-master node, will cause the current
471 a8083063 Iustin Pop
  master to cease being master, and the non-master to become new
472 a8083063 Iustin Pop
  master.
473 a8083063 Iustin Pop
474 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
475 469ee405 Iustin Pop
  @type args: list
476 469ee405 Iustin Pop
  @param args: should be an empty list
477 469ee405 Iustin Pop
  @rtype: int
478 469ee405 Iustin Pop
  @return: the desired exit code
479 469ee405 Iustin Pop
480 a8083063 Iustin Pop
  """
481 8e2524c3 Guido Trotter
  if opts.no_voting:
482 8e2524c3 Guido Trotter
    usertext = ("This will perform the failover even if most other nodes"
483 8e2524c3 Guido Trotter
                " are down, or if this node is outdated. This is dangerous"
484 8e2524c3 Guido Trotter
                " as it can lead to a non-consistent cluster. Check the"
485 8e2524c3 Guido Trotter
                " gnt-cluster(8) man page before proceeding. Continue?")
486 8e2524c3 Guido Trotter
    if not AskUser(usertext):
487 8e2524c3 Guido Trotter
      return 1
488 8e2524c3 Guido Trotter
489 8e2524c3 Guido Trotter
  return bootstrap.MasterFailover(no_voting=opts.no_voting)
490 a8083063 Iustin Pop
491 a8083063 Iustin Pop
492 73415719 Iustin Pop
def SearchTags(opts, args):
493 73415719 Iustin Pop
  """Searches the tags on all the cluster.
494 73415719 Iustin Pop
495 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
496 469ee405 Iustin Pop
  @type args: list
497 469ee405 Iustin Pop
  @param args: should contain only one element, the tag pattern
498 469ee405 Iustin Pop
  @rtype: int
499 469ee405 Iustin Pop
  @return: the desired exit code
500 469ee405 Iustin Pop
501 73415719 Iustin Pop
  """
502 73415719 Iustin Pop
  op = opcodes.OpSearchTags(pattern=args[0])
503 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
504 73415719 Iustin Pop
  if not result:
505 73415719 Iustin Pop
    return 1
506 73415719 Iustin Pop
  result = list(result)
507 73415719 Iustin Pop
  result.sort()
508 73415719 Iustin Pop
  for path, tag in result:
509 3a24c527 Iustin Pop
    ToStdout("%s %s", path, tag)
510 73415719 Iustin Pop
511 73415719 Iustin Pop
512 6d4a1656 Michael Hanselmann
def _RenewCrypto(new_cluster_cert, new_rapi_cert, rapi_cert_filename,
513 6b7d5878 Michael Hanselmann
                 new_confd_hmac_key, force):
514 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
515 6d4a1656 Michael Hanselmann
516 6d4a1656 Michael Hanselmann
  @type new_cluster_cert: bool
517 6d4a1656 Michael Hanselmann
  @param new_cluster_cert: Whether to generate a new cluster certificate
518 6d4a1656 Michael Hanselmann
  @type new_rapi_cert: bool
519 6d4a1656 Michael Hanselmann
  @param new_rapi_cert: Whether to generate a new RAPI certificate
520 6d4a1656 Michael Hanselmann
  @type rapi_cert_filename: string
521 6d4a1656 Michael Hanselmann
  @param rapi_cert_filename: Path to file containing new RAPI certificate
522 6b7d5878 Michael Hanselmann
  @type new_confd_hmac_key: bool
523 6b7d5878 Michael Hanselmann
  @param new_confd_hmac_key: Whether to generate a new HMAC key
524 6d4a1656 Michael Hanselmann
  @type force: bool
525 6d4a1656 Michael Hanselmann
  @param force: Whether to ask user for confirmation
526 6d4a1656 Michael Hanselmann
527 6d4a1656 Michael Hanselmann
  """
528 6d4a1656 Michael Hanselmann
  if new_rapi_cert and rapi_cert_filename:
529 6d4a1656 Michael Hanselmann
    ToStderr("Only one of the --new-rapi-certficate and --rapi-certificate"
530 6d4a1656 Michael Hanselmann
             " options can be specified at the same time.")
531 6d4a1656 Michael Hanselmann
    return 1
532 6d4a1656 Michael Hanselmann
533 6d4a1656 Michael Hanselmann
  if rapi_cert_filename:
534 6d4a1656 Michael Hanselmann
    # Read and verify new certificate
535 6d4a1656 Michael Hanselmann
    try:
536 6d4a1656 Michael Hanselmann
      rapi_cert_pem = utils.ReadFile(rapi_cert_filename)
537 6d4a1656 Michael Hanselmann
538 6d4a1656 Michael Hanselmann
      OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
539 6d4a1656 Michael Hanselmann
                                      rapi_cert_pem)
540 6d4a1656 Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
541 6d4a1656 Michael Hanselmann
      ToStderr("Can't load new RAPI certificate from %s: %s" %
542 6d4a1656 Michael Hanselmann
               (rapi_cert_filename, str(err)))
543 6d4a1656 Michael Hanselmann
      return 1
544 6d4a1656 Michael Hanselmann
545 6d4a1656 Michael Hanselmann
    try:
546 6d4a1656 Michael Hanselmann
      OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, rapi_cert_pem)
547 6d4a1656 Michael Hanselmann
    except Exception, err: # pylint: disable-msg=W0703
548 6d4a1656 Michael Hanselmann
      ToStderr("Can't load new RAPI private key from %s: %s" %
549 6d4a1656 Michael Hanselmann
               (rapi_cert_filename, str(err)))
550 6d4a1656 Michael Hanselmann
      return 1
551 6d4a1656 Michael Hanselmann
552 6d4a1656 Michael Hanselmann
  else:
553 6d4a1656 Michael Hanselmann
    rapi_cert_pem = None
554 6d4a1656 Michael Hanselmann
555 6d4a1656 Michael Hanselmann
  if not force:
556 6d4a1656 Michael Hanselmann
    usertext = ("This requires all daemons on all nodes to be restarted and"
557 6d4a1656 Michael Hanselmann
                " may take some time. Continue?")
558 6d4a1656 Michael Hanselmann
    if not AskUser(usertext):
559 6d4a1656 Michael Hanselmann
      return 1
560 6d4a1656 Michael Hanselmann
561 6d4a1656 Michael Hanselmann
  def _RenewCryptoInner(ctx):
562 6d4a1656 Michael Hanselmann
    ctx.feedback_fn("Updating certificates and keys")
563 6d4a1656 Michael Hanselmann
    bootstrap.GenerateClusterCrypto(new_cluster_cert, new_rapi_cert,
564 6b7d5878 Michael Hanselmann
                                    new_confd_hmac_key,
565 6d4a1656 Michael Hanselmann
                                    rapi_cert_pem=rapi_cert_pem)
566 6d4a1656 Michael Hanselmann
567 6d4a1656 Michael Hanselmann
    files_to_copy = []
568 6d4a1656 Michael Hanselmann
569 6d4a1656 Michael Hanselmann
    if new_cluster_cert:
570 168c1de2 Michael Hanselmann
      files_to_copy.append(constants.NODED_CERT_FILE)
571 6d4a1656 Michael Hanselmann
572 6d4a1656 Michael Hanselmann
    if new_rapi_cert or rapi_cert_pem:
573 6d4a1656 Michael Hanselmann
      files_to_copy.append(constants.RAPI_CERT_FILE)
574 6d4a1656 Michael Hanselmann
575 6b7d5878 Michael Hanselmann
    if new_confd_hmac_key:
576 6b7d5878 Michael Hanselmann
      files_to_copy.append(constants.CONFD_HMAC_KEY)
577 6d4a1656 Michael Hanselmann
578 6d4a1656 Michael Hanselmann
    if files_to_copy:
579 6d4a1656 Michael Hanselmann
      for node_name in ctx.nonmaster_nodes:
580 6d4a1656 Michael Hanselmann
        ctx.feedback_fn("Copying %s to %s" %
581 6d4a1656 Michael Hanselmann
                        (", ".join(files_to_copy), node_name))
582 6d4a1656 Michael Hanselmann
        for file_name in files_to_copy:
583 6d4a1656 Michael Hanselmann
          ctx.ssh.CopyFileToNode(node_name, file_name)
584 6d4a1656 Michael Hanselmann
585 6d4a1656 Michael Hanselmann
  RunWhileClusterStopped(ToStdout, _RenewCryptoInner)
586 6d4a1656 Michael Hanselmann
587 6d4a1656 Michael Hanselmann
  ToStdout("All requested certificates and keys have been replaced."
588 6d4a1656 Michael Hanselmann
           " Running \"gnt-cluster verify\" now is recommended.")
589 6d4a1656 Michael Hanselmann
590 6d4a1656 Michael Hanselmann
  return 0
591 6d4a1656 Michael Hanselmann
592 6d4a1656 Michael Hanselmann
593 6d4a1656 Michael Hanselmann
def RenewCrypto(opts, args):
594 6d4a1656 Michael Hanselmann
  """Renews cluster certificates, keys and secrets.
595 6d4a1656 Michael Hanselmann
596 6d4a1656 Michael Hanselmann
  """
597 6d4a1656 Michael Hanselmann
  return _RenewCrypto(opts.new_cluster_cert,
598 6d4a1656 Michael Hanselmann
                      opts.new_rapi_cert,
599 6d4a1656 Michael Hanselmann
                      opts.rapi_cert,
600 6b7d5878 Michael Hanselmann
                      opts.new_confd_hmac_key,
601 6d4a1656 Michael Hanselmann
                      opts.force)
602 6d4a1656 Michael Hanselmann
603 6d4a1656 Michael Hanselmann
604 90b6aa3a Manuel Franceschini
def SetClusterParams(opts, args):
605 90b6aa3a Manuel Franceschini
  """Modify the cluster.
606 90b6aa3a Manuel Franceschini
607 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
608 469ee405 Iustin Pop
  @type args: list
609 469ee405 Iustin Pop
  @param args: should be an empty list
610 469ee405 Iustin Pop
  @rtype: int
611 469ee405 Iustin Pop
  @return: the desired exit code
612 90b6aa3a Manuel Franceschini
613 90b6aa3a Manuel Franceschini
  """
614 779c15bb Iustin Pop
  if not (not opts.lvm_storage or opts.vg_name or
615 779c15bb Iustin Pop
          opts.enabled_hypervisors or opts.hvparams or
616 5af3da74 Guido Trotter
          opts.beparams or opts.nicparams or
617 3953242f Iustin Pop
          opts.candidate_pool_size is not None or
618 1338f2b4 Balazs Lecz
          opts.uid_pool is not None or
619 fdad8c4d Balazs Lecz
          opts.maintain_node_health is not None or
620 fdad8c4d Balazs Lecz
          opts.add_uids is not None or
621 fdad8c4d Balazs Lecz
          opts.remove_uids is not None):
622 3a24c527 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
623 90b6aa3a Manuel Franceschini
    return 1
624 90b6aa3a Manuel Franceschini
625 90b6aa3a Manuel Franceschini
  vg_name = opts.vg_name
626 90b6aa3a Manuel Franceschini
  if not opts.lvm_storage and opts.vg_name:
627 6d4a1656 Michael Hanselmann
    ToStderr("Options --no-lvm-storage and --vg-name conflict.")
628 90b6aa3a Manuel Franceschini
    return 1
629 6d4a1656 Michael Hanselmann
630 6d4a1656 Michael Hanselmann
  if not opts.lvm_storage:
631 6d4a1656 Michael Hanselmann
    vg_name = ""
632 90b6aa3a Manuel Franceschini
633 779c15bb Iustin Pop
  hvlist = opts.enabled_hypervisors
634 779c15bb Iustin Pop
  if hvlist is not None:
635 779c15bb Iustin Pop
    hvlist = hvlist.split(",")
636 779c15bb Iustin Pop
637 f8e7ddca Guido Trotter
  # a list of (name, dict) we can pass directly to dict() (or [])
638 f8e7ddca Guido Trotter
  hvparams = dict(opts.hvparams)
639 f4ad2ef0 Iustin Pop
  for hv_params in hvparams.values():
640 a5728081 Guido Trotter
    utils.ForceDictType(hv_params, constants.HVS_PARAMETER_TYPES)
641 779c15bb Iustin Pop
642 779c15bb Iustin Pop
  beparams = opts.beparams
643 a5728081 Guido Trotter
  utils.ForceDictType(beparams, constants.BES_PARAMETER_TYPES)
644 779c15bb Iustin Pop
645 5af3da74 Guido Trotter
  nicparams = opts.nicparams
646 5af3da74 Guido Trotter
  utils.ForceDictType(nicparams, constants.NICS_PARAMETER_TYPES)
647 5af3da74 Guido Trotter
648 1338f2b4 Balazs Lecz
649 3953242f Iustin Pop
  mnh = opts.maintain_node_health
650 3953242f Iustin Pop
651 1338f2b4 Balazs Lecz
  uid_pool = opts.uid_pool
652 1338f2b4 Balazs Lecz
  if uid_pool is not None:
653 1338f2b4 Balazs Lecz
    uid_pool = uidpool.ParseUidPool(uid_pool)
654 1338f2b4 Balazs Lecz
655 fdad8c4d Balazs Lecz
  add_uids = opts.add_uids
656 fdad8c4d Balazs Lecz
  if add_uids is not None:
657 fdad8c4d Balazs Lecz
    add_uids = uidpool.ParseUidPool(add_uids)
658 fdad8c4d Balazs Lecz
659 fdad8c4d Balazs Lecz
  remove_uids = opts.remove_uids
660 fdad8c4d Balazs Lecz
  if remove_uids is not None:
661 fdad8c4d Balazs Lecz
    remove_uids = uidpool.ParseUidPool(remove_uids)
662 fdad8c4d Balazs Lecz
663 b8a8fbe1 Guido Trotter
  op = opcodes.OpSetClusterParams(vg_name=vg_name,
664 779c15bb Iustin Pop
                                  enabled_hypervisors=hvlist,
665 779c15bb Iustin Pop
                                  hvparams=hvparams,
666 17463d22 René Nussbaumer
                                  os_hvp=None,
667 4b7735f9 Iustin Pop
                                  beparams=beparams,
668 5af3da74 Guido Trotter
                                  nicparams=nicparams,
669 3953242f Iustin Pop
                                  candidate_pool_size=opts.candidate_pool_size,
670 1338f2b4 Balazs Lecz
                                  maintain_node_health=mnh,
671 fdad8c4d Balazs Lecz
                                  uid_pool=uid_pool,
672 fdad8c4d Balazs Lecz
                                  add_uids=add_uids,
673 fdad8c4d Balazs Lecz
                                  remove_uids=remove_uids)
674 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
675 90b6aa3a Manuel Franceschini
  return 0
676 90b6aa3a Manuel Franceschini
677 90b6aa3a Manuel Franceschini
678 3ccafd0e Iustin Pop
def QueueOps(opts, args):
679 3ccafd0e Iustin Pop
  """Queue operations.
680 3ccafd0e Iustin Pop
681 469ee405 Iustin Pop
  @param opts: the command line options selected by the user
682 469ee405 Iustin Pop
  @type args: list
683 469ee405 Iustin Pop
  @param args: should contain only one element, the subcommand
684 469ee405 Iustin Pop
  @rtype: int
685 469ee405 Iustin Pop
  @return: the desired exit code
686 469ee405 Iustin Pop
687 3ccafd0e Iustin Pop
  """
688 3ccafd0e Iustin Pop
  command = args[0]
689 3ccafd0e Iustin Pop
  client = GetClient()
690 3ccafd0e Iustin Pop
  if command in ("drain", "undrain"):
691 3ccafd0e Iustin Pop
    drain_flag = command == "drain"
692 3ccafd0e Iustin Pop
    client.SetQueueDrainFlag(drain_flag)
693 3ccafd0e Iustin Pop
  elif command == "info":
694 3ccafd0e Iustin Pop
    result = client.QueryConfigValues(["drain_flag"])
695 3ccafd0e Iustin Pop
    if result[0]:
696 3a24c527 Iustin Pop
      val = "set"
697 3ccafd0e Iustin Pop
    else:
698 3a24c527 Iustin Pop
      val = "unset"
699 3a24c527 Iustin Pop
    ToStdout("The drain flag is %s" % val)
700 2e668b38 Guido Trotter
  else:
701 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
702 debac808 Iustin Pop
                               errors.ECODE_INVAL)
703 2e668b38 Guido Trotter
704 3ccafd0e Iustin Pop
  return 0
705 3ccafd0e Iustin Pop
706 95b2e626 Michael Hanselmann
707 28b498cd Michael Hanselmann
def _ShowWatcherPause(until):
708 28b498cd Michael Hanselmann
  if until is None or until < time.time():
709 28b498cd Michael Hanselmann
    ToStdout("The watcher is not paused.")
710 28b498cd Michael Hanselmann
  else:
711 28b498cd Michael Hanselmann
    ToStdout("The watcher is paused until %s.", time.ctime(until))
712 28b498cd Michael Hanselmann
713 28b498cd Michael Hanselmann
714 95b2e626 Michael Hanselmann
def WatcherOps(opts, args):
715 95b2e626 Michael Hanselmann
  """Watcher operations.
716 95b2e626 Michael Hanselmann
717 95b2e626 Michael Hanselmann
  @param opts: the command line options selected by the user
718 95b2e626 Michael Hanselmann
  @type args: list
719 95b2e626 Michael Hanselmann
  @param args: should contain only one element, the subcommand
720 95b2e626 Michael Hanselmann
  @rtype: int
721 95b2e626 Michael Hanselmann
  @return: the desired exit code
722 95b2e626 Michael Hanselmann
723 95b2e626 Michael Hanselmann
  """
724 95b2e626 Michael Hanselmann
  command = args[0]
725 95b2e626 Michael Hanselmann
  client = GetClient()
726 95b2e626 Michael Hanselmann
727 95b2e626 Michael Hanselmann
  if command == "continue":
728 95b2e626 Michael Hanselmann
    client.SetWatcherPause(None)
729 28b498cd Michael Hanselmann
    ToStdout("The watcher is no longer paused.")
730 95b2e626 Michael Hanselmann
731 95b2e626 Michael Hanselmann
  elif command == "pause":
732 95b2e626 Michael Hanselmann
    if len(args) < 2:
733 debac808 Iustin Pop
      raise errors.OpPrereqError("Missing pause duration", errors.ECODE_INVAL)
734 95b2e626 Michael Hanselmann
735 28b498cd Michael Hanselmann
    result = client.SetWatcherPause(time.time() + ParseTimespec(args[1]))
736 28b498cd Michael Hanselmann
    _ShowWatcherPause(result)
737 95b2e626 Michael Hanselmann
738 95b2e626 Michael Hanselmann
  elif command == "info":
739 95b2e626 Michael Hanselmann
    result = client.QueryConfigValues(["watcher_pause"])
740 cac599f1 Michael Hanselmann
    _ShowWatcherPause(result[0])
741 95b2e626 Michael Hanselmann
742 95b2e626 Michael Hanselmann
  else:
743 debac808 Iustin Pop
    raise errors.OpPrereqError("Command '%s' is not valid." % command,
744 debac808 Iustin Pop
                               errors.ECODE_INVAL)
745 95b2e626 Michael Hanselmann
746 95b2e626 Michael Hanselmann
  return 0
747 95b2e626 Michael Hanselmann
748 95b2e626 Michael Hanselmann
749 a8083063 Iustin Pop
commands = {
750 6ea815cf Iustin Pop
  'init': (
751 6ea815cf Iustin Pop
    InitCluster, [ArgHost(min=1, max=1)],
752 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, GLOBAL_FILEDIR_OPT,
753 6ea815cf Iustin Pop
     HVLIST_OPT, MAC_PREFIX_OPT, MASTER_NETDEV_OPT, NIC_PARAMS_OPT,
754 b989b9d9 Ken Wehr
     NOLVM_STORAGE_OPT, NOMODIFY_ETCHOSTS_OPT, NOMODIFY_SSH_SETUP_OPT,
755 39b0f0c2 Balazs Lecz
     SECONDARY_IP_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
756 39b0f0c2 Balazs Lecz
     UIDPOOL_OPT],
757 6ea815cf Iustin Pop
    "[opts...] <cluster_name>", "Initialises a new cluster configuration"),
758 6ea815cf Iustin Pop
  'destroy': (
759 064c21f8 Iustin Pop
    DestroyCluster, ARGS_NONE, [YES_DOIT_OPT],
760 6ea815cf Iustin Pop
    "", "Destroy cluster"),
761 6ea815cf Iustin Pop
  'rename': (
762 6ea815cf Iustin Pop
    RenameCluster, [ArgHost(min=1, max=1)],
763 064c21f8 Iustin Pop
    [FORCE_OPT],
764 6ea815cf Iustin Pop
    "<new_name>",
765 6ea815cf Iustin Pop
    "Renames the cluster"),
766 6ea815cf Iustin Pop
  'redist-conf': (
767 064c21f8 Iustin Pop
    RedistributeConfig, ARGS_NONE, [SUBMIT_OPT],
768 6ea815cf Iustin Pop
    "", "Forces a push of the configuration file and ssconf files"
769 6ea815cf Iustin Pop
    " to the nodes in the cluster"),
770 6ea815cf Iustin Pop
  'verify': (
771 6ea815cf Iustin Pop
    VerifyCluster, ARGS_NONE,
772 064c21f8 Iustin Pop
    [VERBOSE_OPT, DEBUG_SIMERR_OPT, ERROR_CODES_OPT, NONPLUS1_OPT],
773 6ea815cf Iustin Pop
    "", "Does a check on the cluster configuration"),
774 6ea815cf Iustin Pop
  'verify-disks': (
775 064c21f8 Iustin Pop
    VerifyDisks, ARGS_NONE, [],
776 6ea815cf Iustin Pop
    "", "Does a check on the cluster disk status"),
777 6ea815cf Iustin Pop
  'repair-disk-sizes': (
778 064c21f8 Iustin Pop
    RepairDiskSizes, ARGS_MANY_INSTANCES, [],
779 6ea815cf Iustin Pop
    "", "Updates mismatches in recorded disk sizes"),
780 6ea815cf Iustin Pop
  'masterfailover': (
781 064c21f8 Iustin Pop
    MasterFailover, ARGS_NONE, [NOVOTING_OPT],
782 6ea815cf Iustin Pop
    "", "Makes the current node the master"),
783 6ea815cf Iustin Pop
  'version': (
784 064c21f8 Iustin Pop
    ShowClusterVersion, ARGS_NONE, [],
785 6ea815cf Iustin Pop
    "", "Shows the cluster version"),
786 6ea815cf Iustin Pop
  'getmaster': (
787 064c21f8 Iustin Pop
    ShowClusterMaster, ARGS_NONE, [],
788 6ea815cf Iustin Pop
    "", "Shows the cluster master"),
789 6ea815cf Iustin Pop
  'copyfile': (
790 6ea815cf Iustin Pop
    ClusterCopyFile, [ArgFile(min=1, max=1)],
791 74adc100 Iustin Pop
    [NODE_LIST_OPT, USE_REPL_NET_OPT],
792 6ea815cf Iustin Pop
    "[-n node...] <filename>", "Copies a file to all (or only some) nodes"),
793 6ea815cf Iustin Pop
  'command': (
794 6ea815cf Iustin Pop
    RunClusterCommand, [ArgCommand(min=1)],
795 064c21f8 Iustin Pop
    [NODE_LIST_OPT],
796 6ea815cf Iustin Pop
    "[-n node...] <command>", "Runs a command on all (or only some) nodes"),
797 6ea815cf Iustin Pop
  'info': (
798 d729e03a Guido Trotter
    ShowClusterConfig, ARGS_NONE, [ROMAN_OPT],
799 d729e03a Guido Trotter
    "[--roman]", "Show cluster configuration"),
800 6ea815cf Iustin Pop
  'list-tags': (
801 064c21f8 Iustin Pop
    ListTags, ARGS_NONE, [], "", "List the tags of the cluster"),
802 6ea815cf Iustin Pop
  'add-tags': (
803 064c21f8 Iustin Pop
    AddTags, [ArgUnknown()], [TAG_SRC_OPT],
804 6ea815cf Iustin Pop
    "tag...", "Add tags to the cluster"),
805 6ea815cf Iustin Pop
  'remove-tags': (
806 064c21f8 Iustin Pop
    RemoveTags, [ArgUnknown()], [TAG_SRC_OPT],
807 6ea815cf Iustin Pop
    "tag...", "Remove tags from the cluster"),
808 6ea815cf Iustin Pop
  'search-tags': (
809 6ea815cf Iustin Pop
    SearchTags, [ArgUnknown(min=1, max=1)],
810 064c21f8 Iustin Pop
    [], "", "Searches the tags on all objects on"
811 6ea815cf Iustin Pop
    " the cluster for a given pattern (regex)"),
812 6ea815cf Iustin Pop
  'queue': (
813 6ea815cf Iustin Pop
    QueueOps,
814 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["drain", "undrain", "info"])],
815 064c21f8 Iustin Pop
    [], "drain|undrain|info", "Change queue properties"),
816 6ea815cf Iustin Pop
  'watcher': (
817 6ea815cf Iustin Pop
    WatcherOps,
818 6ea815cf Iustin Pop
    [ArgChoice(min=1, max=1, choices=["pause", "continue", "info"]),
819 6ea815cf Iustin Pop
     ArgSuggest(min=0, max=1, choices=["30m", "1h", "4h"])],
820 064c21f8 Iustin Pop
    [],
821 6ea815cf Iustin Pop
    "{pause <timespec>|continue|info}", "Change watcher properties"),
822 6ea815cf Iustin Pop
  'modify': (
823 6ea815cf Iustin Pop
    SetClusterParams, ARGS_NONE,
824 064c21f8 Iustin Pop
    [BACKEND_OPT, CP_SIZE_OPT, ENABLED_HV_OPT, HVLIST_OPT,
825 1338f2b4 Balazs Lecz
     NIC_PARAMS_OPT, NOLVM_STORAGE_OPT, VG_NAME_OPT, MAINTAIN_NODE_HEALTH_OPT,
826 fdad8c4d Balazs Lecz
     UIDPOOL_OPT, ADD_UIDS_OPT, REMOVE_UIDS_OPT],
827 6ea815cf Iustin Pop
    "[opts...]",
828 6ea815cf Iustin Pop
    "Alters the parameters of the cluster"),
829 6d4a1656 Michael Hanselmann
  "renew-crypto": (
830 6d4a1656 Michael Hanselmann
    RenewCrypto, ARGS_NONE,
831 6b7d5878 Michael Hanselmann
    [NEW_CLUSTER_CERT_OPT, NEW_RAPI_CERT_OPT, RAPI_CERT_OPT,
832 6b7d5878 Michael Hanselmann
     NEW_CONFD_HMAC_KEY_OPT, FORCE_OPT],
833 6d4a1656 Michael Hanselmann
    "[opts...]",
834 6d4a1656 Michael Hanselmann
    "Renews cluster certificates, keys and secrets"),
835 a8083063 Iustin Pop
  }
836 a8083063 Iustin Pop
837 6d4a1656 Michael Hanselmann
838 a8083063 Iustin Pop
if __name__ == '__main__':
839 846baef9 Iustin Pop
  sys.exit(GenericMain(commands, override={"tag_type": constants.TAG_CLUSTER}))