Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 65a77fab

History | View | Annotate | Download (29.2 kB)

1 37494fa4 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 668f755d Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 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
"""Node 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-node
28 2f79bd34 Iustin Pop
29 a8083063 Iustin Pop
from ganeti.cli import *
30 d363797e René Nussbaumer
from ganeti import cli
31 3ef51126 René Nussbaumer
from ganeti import bootstrap
32 a8083063 Iustin Pop
from ganeti import opcodes
33 a8083063 Iustin Pop
from ganeti import utils
34 846baef9 Iustin Pop
from ganeti import constants
35 c450e9b0 Iustin Pop
from ganeti import errors
36 a744b676 Manuel Franceschini
from ganeti import netutils
37 8572f1fe René Nussbaumer
from cStringIO import StringIO
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
40 ebf366ee Iustin Pop
#: default list of field for L{ListNodes}
41 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
42 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
43 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
44 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
45 48c4dfa8 Iustin Pop
  ]
46 48c4dfa8 Iustin Pop
47 620a85fd Iustin Pop
48 a4ebd726 Michael Hanselmann
#: Default field list for L{ListVolumes}
49 a4ebd726 Michael Hanselmann
_LIST_VOL_DEF_FIELDS = ["node", "phys", "vg", "name", "size", "instance"]
50 a4ebd726 Michael Hanselmann
51 a4ebd726 Michael Hanselmann
52 620a85fd Iustin Pop
#: default list of field for L{ListStorage}
53 620a85fd Iustin Pop
_LIST_STOR_DEF_FIELDS = [
54 620a85fd Iustin Pop
  constants.SF_NODE,
55 620a85fd Iustin Pop
  constants.SF_TYPE,
56 620a85fd Iustin Pop
  constants.SF_NAME,
57 620a85fd Iustin Pop
  constants.SF_SIZE,
58 620a85fd Iustin Pop
  constants.SF_USED,
59 620a85fd Iustin Pop
  constants.SF_FREE,
60 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE,
61 620a85fd Iustin Pop
  ]
62 620a85fd Iustin Pop
63 620a85fd Iustin Pop
64 abefdcff René Nussbaumer
#: default list of power commands
65 abefdcff René Nussbaumer
_LIST_POWER_COMMANDS = ["on", "off", "cycle", "status"]
66 abefdcff René Nussbaumer
67 abefdcff René Nussbaumer
68 982ed68e Adeodato Simo
#: headers (and full field list) for L{ListStorage}
69 620a85fd Iustin Pop
_LIST_STOR_HEADERS = {
70 620a85fd Iustin Pop
  constants.SF_NODE: "Node",
71 620a85fd Iustin Pop
  constants.SF_TYPE: "Type",
72 620a85fd Iustin Pop
  constants.SF_NAME: "Name",
73 620a85fd Iustin Pop
  constants.SF_SIZE: "Size",
74 620a85fd Iustin Pop
  constants.SF_USED: "Used",
75 620a85fd Iustin Pop
  constants.SF_FREE: "Free",
76 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE: "Allocatable",
77 620a85fd Iustin Pop
  }
78 620a85fd Iustin Pop
79 620a85fd Iustin Pop
80 0e89fc2d Michael Hanselmann
#: User-facing storage unit types
81 0e89fc2d Michael Hanselmann
_USER_STORAGE_TYPE = {
82 0e89fc2d Michael Hanselmann
  constants.ST_FILE: "file",
83 0e89fc2d Michael Hanselmann
  constants.ST_LVM_PV: "lvm-pv",
84 0e89fc2d Michael Hanselmann
  constants.ST_LVM_VG: "lvm-vg",
85 0e89fc2d Michael Hanselmann
  }
86 0e89fc2d Michael Hanselmann
87 a8005e17 Michael Hanselmann
_STORAGE_TYPE_OPT = \
88 aeaefce8 Iustin Pop
  cli_option("-t", "--storage-type",
89 a8005e17 Michael Hanselmann
             dest="user_storage_type",
90 a8005e17 Michael Hanselmann
             choices=_USER_STORAGE_TYPE.keys(),
91 a8005e17 Michael Hanselmann
             default=None,
92 a8005e17 Michael Hanselmann
             metavar="STORAGE_TYPE",
93 ab3e6da8 Iustin Pop
             help=("Storage type (%s)" %
94 ab3e6da8 Iustin Pop
                   utils.CommaJoin(_USER_STORAGE_TYPE.keys())))
95 a8005e17 Michael Hanselmann
96 a8005e17 Michael Hanselmann
_REPAIRABLE_STORAGE_TYPES = \
97 a8005e17 Michael Hanselmann
  [st for st, so in constants.VALID_STORAGE_OPERATIONS.iteritems()
98 a8005e17 Michael Hanselmann
   if constants.SO_FIX_CONSISTENCY in so]
99 a8005e17 Michael Hanselmann
100 a8005e17 Michael Hanselmann
_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys()
101 a8005e17 Michael Hanselmann
102 51144e33 Michael Hanselmann
103 c832b6c8 René Nussbaumer
_OOB_COMMAND_ASK = frozenset([constants.OOB_POWER_OFF,
104 c832b6c8 René Nussbaumer
                              constants.OOB_POWER_CYCLE])
105 c832b6c8 René Nussbaumer
106 c832b6c8 René Nussbaumer
107 2e6469a1 René Nussbaumer
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True,
108 2e6469a1 René Nussbaumer
                              action="store_false", dest="node_setup",
109 2e6469a1 René Nussbaumer
                              help=("Do not make initial SSH setup on remote"
110 2e6469a1 René Nussbaumer
                                    " node (needs to be done manually)"))
111 2e6469a1 René Nussbaumer
112 efae0fdd René Nussbaumer
IGNORE_STATUS_OPT = cli_option("--ignore-status", default=False,
113 efae0fdd René Nussbaumer
                               action="store_true", dest="ignore_status",
114 efae0fdd René Nussbaumer
                               help=("Ignore the Node(s) offline status"
115 efae0fdd René Nussbaumer
                                     " (potentially DANGEROUS)"))
116 efae0fdd René Nussbaumer
117 efae0fdd René Nussbaumer
FORCE_MASTER_OPT = cli_option("--force-master", default=False,
118 efae0fdd René Nussbaumer
                              action="store_true", dest="force_master",
119 efae0fdd René Nussbaumer
                              help=("Operate on the master node too"
120 efae0fdd René Nussbaumer
                                    " (potentially DANGEROUS)"))
121 efae0fdd René Nussbaumer
122 65a77fab René Nussbaumer
OOB_TIMEOUT_OPT = cli_option("--oob-timeout", dest="oob_timeout", type="int",
123 65a77fab René Nussbaumer
                         default=constants.OOB_TIMEOUT,
124 65a77fab René Nussbaumer
                         help="Maximum time to wait for out-of-band helper")
125 65a77fab René Nussbaumer
126 2e6469a1 René Nussbaumer
127 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
128 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
129 86f5eae3 Michael Hanselmann

130 86f5eae3 Michael Hanselmann
  """
131 86f5eae3 Michael Hanselmann
  try:
132 86f5eae3 Michael Hanselmann
    return _USER_STORAGE_TYPE[user_storage_type]
133 86f5eae3 Michael Hanselmann
  except KeyError:
134 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown storage type: %s" % user_storage_type,
135 debac808 Iustin Pop
                               errors.ECODE_INVAL)
136 86f5eae3 Michael Hanselmann
137 86f5eae3 Michael Hanselmann
138 2e6469a1 René Nussbaumer
def _RunSetupSSH(options, nodes):
139 2e6469a1 René Nussbaumer
  """Wrapper around utils.RunCmd to call setup-ssh
140 2e6469a1 René Nussbaumer

141 2e6469a1 René Nussbaumer
  @param options: The command line options
142 2e6469a1 René Nussbaumer
  @param nodes: The nodes to setup
143 2e6469a1 René Nussbaumer

144 2e6469a1 René Nussbaumer
  """
145 2e6469a1 René Nussbaumer
  cmd = [constants.SETUP_SSH]
146 2e6469a1 René Nussbaumer
147 2e6469a1 René Nussbaumer
  # Pass --debug|--verbose to the external script if set on our invocation
148 2e6469a1 René Nussbaumer
  # --debug overrides --verbose
149 2e6469a1 René Nussbaumer
  if options.debug:
150 2e6469a1 René Nussbaumer
    cmd.append("--debug")
151 2e6469a1 René Nussbaumer
  elif options.verbose:
152 2e6469a1 René Nussbaumer
    cmd.append("--verbose")
153 e81edf72 Manuel Franceschini
  if not options.ssh_key_check:
154 3ef51126 René Nussbaumer
    cmd.append("--no-ssh-key-check")
155 2e6469a1 René Nussbaumer
156 2e6469a1 René Nussbaumer
  cmd.extend(nodes)
157 2e6469a1 René Nussbaumer
158 2e6469a1 René Nussbaumer
  result = utils.RunCmd(cmd, interactive=True)
159 2e6469a1 René Nussbaumer
160 2e6469a1 René Nussbaumer
  if result.failed:
161 2e6469a1 René Nussbaumer
    errmsg = ("Command '%s' failed with exit code %s; output %r" %
162 2e6469a1 René Nussbaumer
              (result.cmd, result.exit_code, result.output))
163 2e6469a1 René Nussbaumer
    raise errors.OpExecError(errmsg)
164 2e6469a1 René Nussbaumer
165 2e6469a1 René Nussbaumer
166 4331f6cd Michael Hanselmann
@UsesRPC
167 a8083063 Iustin Pop
def AddNode(opts, args):
168 ebf366ee Iustin Pop
  """Add a node to the cluster.
169 ebf366ee Iustin Pop

170 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
171 ebf366ee Iustin Pop
  @type args: list
172 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
173 ebf366ee Iustin Pop
  @rtype: int
174 ebf366ee Iustin Pop
  @return: the desired exit code
175 05ccd983 Guido Trotter

176 05ccd983 Guido Trotter
  """
177 87622829 Iustin Pop
  cl = GetClient()
178 b705c7a6 Manuel Franceschini
  node = netutils.GetHostname(name=args[0]).name
179 82e12743 Iustin Pop
  readd = opts.readd
180 82e12743 Iustin Pop
181 82e12743 Iustin Pop
  try:
182 82e12743 Iustin Pop
    output = cl.QueryNodes(names=[node], fields=['name', 'sip'],
183 77921a95 Iustin Pop
                           use_locking=False)
184 82e12743 Iustin Pop
    node_exists, sip = output[0]
185 82e12743 Iustin Pop
  except (errors.OpPrereqError, errors.OpExecError):
186 82e12743 Iustin Pop
    node_exists = ""
187 82e12743 Iustin Pop
    sip = None
188 82e12743 Iustin Pop
189 82e12743 Iustin Pop
  if readd:
190 82e12743 Iustin Pop
    if not node_exists:
191 82e12743 Iustin Pop
      ToStderr("Node %s not in the cluster"
192 82e12743 Iustin Pop
               " - please retry without '--readd'", node)
193 82e12743 Iustin Pop
      return 1
194 82e12743 Iustin Pop
  else:
195 82e12743 Iustin Pop
    if node_exists:
196 3a24c527 Iustin Pop
      ToStderr("Node %s already in the cluster (as %s)"
197 82e12743 Iustin Pop
               " - please retry with '--readd'", node, node_exists)
198 05ccd983 Guido Trotter
      return 1
199 82e12743 Iustin Pop
    sip = opts.secondary_ip
200 05ccd983 Guido Trotter
201 87622829 Iustin Pop
  # read the cluster name from the master
202 87622829 Iustin Pop
  output = cl.QueryConfigValues(['cluster_name'])
203 3ef51126 René Nussbaumer
  cluster_name = output[0]
204 87622829 Iustin Pop
205 3ef51126 René Nussbaumer
  if not readd and opts.node_setup:
206 82e12743 Iustin Pop
    ToStderr("-- WARNING -- \n"
207 82e12743 Iustin Pop
             "Performing this operation is going to replace the ssh daemon"
208 82e12743 Iustin Pop
             " keypair\n"
209 82e12743 Iustin Pop
             "on the target machine (%s) with the ones of the"
210 82e12743 Iustin Pop
             " current one\n"
211 82e12743 Iustin Pop
             "and grant full intra-cluster ssh root access to/from it\n", node)
212 05ccd983 Guido Trotter
213 2e6469a1 René Nussbaumer
  if opts.node_setup:
214 2e6469a1 René Nussbaumer
    _RunSetupSSH(opts, [node])
215 827f753e Guido Trotter
216 3ef51126 René Nussbaumer
  bootstrap.SetupNodeDaemon(cluster_name, node, opts.ssh_key_check)
217 3ef51126 René Nussbaumer
218 d817d49f Iustin Pop
  op = opcodes.OpNodeAdd(node_name=args[0], secondary_ip=sip,
219 fd3d37b6 Iustin Pop
                         readd=opts.readd, group=opts.nodegroup,
220 4e37f591 René Nussbaumer
                         vm_capable=opts.vm_capable, ndparams=opts.ndparams,
221 fd3d37b6 Iustin Pop
                         master_capable=opts.master_capable)
222 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
223 a8083063 Iustin Pop
224 a8083063 Iustin Pop
225 a8083063 Iustin Pop
def ListNodes(opts, args):
226 a8083063 Iustin Pop
  """List nodes and their properties.
227 a8083063 Iustin Pop

228 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
229 ebf366ee Iustin Pop
  @type args: list
230 982ed68e Adeodato Simo
  @param args: nodes to list, or empty for all
231 ebf366ee Iustin Pop
  @rtype: int
232 ebf366ee Iustin Pop
  @return: the desired exit code
233 ebf366ee Iustin Pop

234 a8083063 Iustin Pop
  """
235 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
236 a8083063 Iustin Pop
237 7f5443a0 Michael Hanselmann
  fmtoverride = dict.fromkeys(["pinst_list", "sinst_list", "tags"],
238 a36f605d Michael Hanselmann
                              (",".join, False))
239 a8083063 Iustin Pop
240 7f5443a0 Michael Hanselmann
  return GenericList(constants.QR_NODE, selected_fields, args, opts.units,
241 7f5443a0 Michael Hanselmann
                     opts.separator, not opts.no_headers,
242 7f5443a0 Michael Hanselmann
                     format_override=fmtoverride)
243 137161c9 Michael Hanselmann
244 137161c9 Michael Hanselmann
245 7f5443a0 Michael Hanselmann
def ListNodeFields(opts, args):
246 7f5443a0 Michael Hanselmann
  """List node fields.
247 ec223efb Iustin Pop

248 7f5443a0 Michael Hanselmann
  @param opts: the command line options selected by the user
249 7f5443a0 Michael Hanselmann
  @type args: list
250 7f5443a0 Michael Hanselmann
  @param args: fields to list, or empty for all
251 7f5443a0 Michael Hanselmann
  @rtype: int
252 7f5443a0 Michael Hanselmann
  @return: the desired exit code
253 a8083063 Iustin Pop

254 7f5443a0 Michael Hanselmann
  """
255 7f5443a0 Michael Hanselmann
  return GenericListFields(constants.QR_NODE, args, opts.separator,
256 7f5443a0 Michael Hanselmann
                           not opts.no_headers)
257 a8083063 Iustin Pop
258 a8083063 Iustin Pop
259 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
260 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
261 a5bc662a Iustin Pop

262 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
263 ebf366ee Iustin Pop
  @type args: list
264 ebf366ee Iustin Pop
  @param args: should be an empty list
265 ebf366ee Iustin Pop
  @rtype: int
266 ebf366ee Iustin Pop
  @return: the desired exit code
267 ebf366ee Iustin Pop

268 a5bc662a Iustin Pop
  """
269 479636a3 Iustin Pop
  cl = GetClient()
270 a5bc662a Iustin Pop
  force = opts.force
271 c4ed32cb Iustin Pop
272 c4ed32cb Iustin Pop
  dst_node = opts.dst_node
273 c4ed32cb Iustin Pop
  iallocator = opts.iallocator
274 c4ed32cb Iustin Pop
275 0ae89533 Iustin Pop
  op = opcodes.OpNodeEvacStrategy(nodes=args,
276 0ae89533 Iustin Pop
                                  iallocator=iallocator,
277 0ae89533 Iustin Pop
                                  remote_node=dst_node)
278 f8c9fa5c Iustin Pop
279 f8c9fa5c Iustin Pop
  result = SubmitOpCode(op, cl=cl, opts=opts)
280 f8c9fa5c Iustin Pop
  if not result:
281 f8c9fa5c Iustin Pop
    # no instances to migrate
282 f8c9fa5c Iustin Pop
    ToStderr("No secondary instances on node(s) %s, exiting.",
283 f8c9fa5c Iustin Pop
             utils.CommaJoin(args))
284 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
285 a5bc662a Iustin Pop
286 f8c9fa5c Iustin Pop
  if not force and not AskUser("Relocate instance(s) %s from node(s) %s?" %
287 f8c9fa5c Iustin Pop
                               (",".join("'%s'" % name[0] for name in result),
288 f8c9fa5c Iustin Pop
                               utils.CommaJoin(args))):
289 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
290 a5bc662a Iustin Pop
291 f8c9fa5c Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
292 f8c9fa5c Iustin Pop
  for row in result:
293 f8c9fa5c Iustin Pop
    iname = row[0]
294 f8c9fa5c Iustin Pop
    node = row[1]
295 f8c9fa5c Iustin Pop
    ToStdout("Will relocate instance %s to node %s", iname, node)
296 668f755d Iustin Pop
    op = opcodes.OpInstanceReplaceDisks(instance_name=iname,
297 668f755d Iustin Pop
                                        remote_node=node, disks=[],
298 668f755d Iustin Pop
                                        mode=constants.REPLACE_DISK_CHG,
299 668f755d Iustin Pop
                                        early_release=opts.early_release)
300 f8c9fa5c Iustin Pop
    jex.QueueJob(iname, op)
301 f8c9fa5c Iustin Pop
  results = jex.GetResults()
302 f8c9fa5c Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
303 f8c9fa5c Iustin Pop
  if bad_cnt == 0:
304 f8c9fa5c Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
305 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_SUCCESS
306 f8c9fa5c Iustin Pop
  else:
307 f8c9fa5c Iustin Pop
    ToStdout("There were errors during the failover:\n"
308 f8c9fa5c Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
309 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_FAILURE
310 f8c9fa5c Iustin Pop
  return rcode
311 a5bc662a Iustin Pop
312 a5bc662a Iustin Pop
313 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
314 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
315 c450e9b0 Iustin Pop

316 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
317 ebf366ee Iustin Pop
  @type args: list
318 ebf366ee Iustin Pop
  @param args: should be an empty list
319 ebf366ee Iustin Pop
  @rtype: int
320 ebf366ee Iustin Pop
  @return: the desired exit code
321 ebf366ee Iustin Pop

322 c450e9b0 Iustin Pop
  """
323 479636a3 Iustin Pop
  cl = GetClient()
324 c450e9b0 Iustin Pop
  force = opts.force
325 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
326 c450e9b0 Iustin Pop
327 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
328 2e7b8369 Iustin Pop
  # locking=True should be safer
329 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
330 77921a95 Iustin Pop
                         use_locking=False)
331 c450e9b0 Iustin Pop
  node, pinst = result[0]
332 c450e9b0 Iustin Pop
333 c450e9b0 Iustin Pop
  if not pinst:
334 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
335 c450e9b0 Iustin Pop
    return 0
336 c450e9b0 Iustin Pop
337 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
338 c450e9b0 Iustin Pop
339 c450e9b0 Iustin Pop
  retcode = 0
340 c450e9b0 Iustin Pop
341 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
342 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
343 c450e9b0 Iustin Pop
    return 2
344 c450e9b0 Iustin Pop
345 cb573a31 Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
346 c450e9b0 Iustin Pop
  for iname in pinst:
347 019dbee1 Iustin Pop
    op = opcodes.OpInstanceFailover(instance_name=iname,
348 c450e9b0 Iustin Pop
                                    ignore_consistency=opts.ignore_consistency)
349 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
350 479636a3 Iustin Pop
  results = jex.GetResults()
351 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
352 479636a3 Iustin Pop
  if bad_cnt == 0:
353 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
354 c450e9b0 Iustin Pop
  else:
355 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
356 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
357 c450e9b0 Iustin Pop
  return retcode
358 c450e9b0 Iustin Pop
359 c450e9b0 Iustin Pop
360 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
361 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
362 40ef0ed6 Iustin Pop

363 40ef0ed6 Iustin Pop
  """
364 40ef0ed6 Iustin Pop
  cl = GetClient()
365 40ef0ed6 Iustin Pop
  force = opts.force
366 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
367 40ef0ed6 Iustin Pop
368 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
369 40ef0ed6 Iustin Pop
  node, pinst = result[0]
370 40ef0ed6 Iustin Pop
371 40ef0ed6 Iustin Pop
  if not pinst:
372 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
373 40ef0ed6 Iustin Pop
    return 0
374 40ef0ed6 Iustin Pop
375 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
376 40ef0ed6 Iustin Pop
377 40ef0ed6 Iustin Pop
  if not force and not AskUser("Migrate instance(s) %s?" %
378 40ef0ed6 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
379 40ef0ed6 Iustin Pop
    return 2
380 40ef0ed6 Iustin Pop
381 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
382 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
383 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
384 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
385 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
386 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
387 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
388 e71b9ef4 Iustin Pop
  else:
389 8c35561f Iustin Pop
    mode = opts.migration_mode
390 5b14a488 Iustin Pop
  op = opcodes.OpNodeMigrate(node_name=args[0], mode=mode)
391 400ca2f7 Iustin Pop
  SubmitOpCode(op, cl=cl, opts=opts)
392 40ef0ed6 Iustin Pop
393 40ef0ed6 Iustin Pop
394 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
395 a8083063 Iustin Pop
  """Show node information.
396 a8083063 Iustin Pop

397 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
398 ebf366ee Iustin Pop
  @type args: list
399 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
400 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
401 ebf366ee Iustin Pop
      a list of nodes to be queried for information
402 ebf366ee Iustin Pop
  @rtype: int
403 ebf366ee Iustin Pop
  @return: the desired exit code
404 ebf366ee Iustin Pop

405 a8083063 Iustin Pop
  """
406 2e7b8369 Iustin Pop
  cl = GetClient()
407 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
408 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
409 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
410 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
411 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
412 77921a95 Iustin Pop
                         names=args, use_locking=False)
413 a8083063 Iustin Pop
414 8572f1fe René Nussbaumer
  for (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
415 8572f1fe René Nussbaumer
       master_capable, vm_capable, powered, ndparams,
416 8572f1fe René Nussbaumer
       ndparams_custom) in result:
417 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
418 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
419 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
420 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
421 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
422 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
423 016acd85 René Nussbaumer
    if powered is not None:
424 016acd85 René Nussbaumer
      ToStdout("  powered: %s", powered)
425 7b4978ad Iustin Pop
    ToStdout("  master_capable: %s", master_capable)
426 7b4978ad Iustin Pop
    ToStdout("  vm_capable: %s", vm_capable)
427 7b4978ad Iustin Pop
    if vm_capable:
428 7b4978ad Iustin Pop
      if pinst:
429 7b4978ad Iustin Pop
        ToStdout("  primary for instances:")
430 7b4978ad Iustin Pop
        for iname in utils.NiceSort(pinst):
431 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
432 7b4978ad Iustin Pop
      else:
433 7b4978ad Iustin Pop
        ToStdout("  primary for no instances")
434 7b4978ad Iustin Pop
      if sinst:
435 7b4978ad Iustin Pop
        ToStdout("  secondary for instances:")
436 7b4978ad Iustin Pop
        for iname in utils.NiceSort(sinst):
437 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
438 7b4978ad Iustin Pop
      else:
439 7b4978ad Iustin Pop
        ToStdout("  secondary for no instances")
440 8572f1fe René Nussbaumer
    ToStdout("  node parameters:")
441 8572f1fe René Nussbaumer
    buf = StringIO()
442 8572f1fe René Nussbaumer
    FormatParameterDict(buf, ndparams_custom, ndparams, level=2)
443 8572f1fe René Nussbaumer
    ToStdout(buf.getvalue().rstrip("\n"))
444 a8083063 Iustin Pop
445 a8083063 Iustin Pop
  return 0
446 a8083063 Iustin Pop
447 a8083063 Iustin Pop
448 a8083063 Iustin Pop
def RemoveNode(opts, args):
449 ebf366ee Iustin Pop
  """Remove a node from the cluster.
450 ebf366ee Iustin Pop

451 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
452 ebf366ee Iustin Pop
  @type args: list
453 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
454 ebf366ee Iustin Pop
      the node to be removed
455 ebf366ee Iustin Pop
  @rtype: int
456 ebf366ee Iustin Pop
  @return: the desired exit code
457 ebf366ee Iustin Pop

458 ebf366ee Iustin Pop
  """
459 73d565a3 Iustin Pop
  op = opcodes.OpNodeRemove(node_name=args[0])
460 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
461 ebf366ee Iustin Pop
  return 0
462 a8083063 Iustin Pop
463 a8083063 Iustin Pop
464 f5118ade Iustin Pop
def PowercycleNode(opts, args):
465 f5118ade Iustin Pop
  """Remove a node from the cluster.
466 f5118ade Iustin Pop

467 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
468 f5118ade Iustin Pop
  @type args: list
469 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
470 f5118ade Iustin Pop
      the node to be removed
471 f5118ade Iustin Pop
  @rtype: int
472 f5118ade Iustin Pop
  @return: the desired exit code
473 f5118ade Iustin Pop

474 f5118ade Iustin Pop
  """
475 f5118ade Iustin Pop
  node = args[0]
476 f5118ade Iustin Pop
  if (not opts.confirm and
477 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
478 f5118ade Iustin Pop
    return 2
479 f5118ade Iustin Pop
480 e0d4735f Iustin Pop
  op = opcodes.OpNodePowercycle(node_name=node, force=opts.force)
481 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
482 48418fea Iustin Pop
  if result:
483 48418fea Iustin Pop
    ToStderr(result)
484 f5118ade Iustin Pop
  return 0
485 f5118ade Iustin Pop
486 f5118ade Iustin Pop
487 abefdcff René Nussbaumer
def PowerNode(opts, args):
488 abefdcff René Nussbaumer
  """Change/ask power state of a node.
489 abefdcff René Nussbaumer

490 abefdcff René Nussbaumer
  @param opts: the command line options selected by the user
491 abefdcff René Nussbaumer
  @type args: list
492 abefdcff René Nussbaumer
  @param args: should contain only one element, the name of
493 abefdcff René Nussbaumer
      the node to be removed
494 abefdcff René Nussbaumer
  @rtype: int
495 abefdcff René Nussbaumer
  @return: the desired exit code
496 abefdcff René Nussbaumer

497 abefdcff René Nussbaumer
  """
498 c832b6c8 René Nussbaumer
  client = GetClient()
499 c832b6c8 René Nussbaumer
  command = args.pop(0)
500 c832b6c8 René Nussbaumer
501 c832b6c8 René Nussbaumer
  if opts.no_headers:
502 c832b6c8 René Nussbaumer
    headers = None
503 c832b6c8 René Nussbaumer
  else:
504 c832b6c8 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
505 abefdcff René Nussbaumer
506 abefdcff René Nussbaumer
  if command not in _LIST_POWER_COMMANDS:
507 abefdcff René Nussbaumer
    ToStderr("power subcommand %s not supported." % command)
508 abefdcff René Nussbaumer
    return constants.EXIT_FAILURE
509 abefdcff René Nussbaumer
510 c832b6c8 René Nussbaumer
  nodes = [node for (node, ) in client.QueryNodes(args, ["name"], False)]
511 abefdcff René Nussbaumer
  oob_command = "power-%s" % command
512 abefdcff René Nussbaumer
513 c832b6c8 René Nussbaumer
  if oob_command in _OOB_COMMAND_ASK:
514 c832b6c8 René Nussbaumer
    if not args and not opts.show_all:
515 c832b6c8 René Nussbaumer
      ToStderr("Please provide at least one node or use --all for this command"
516 c832b6c8 René Nussbaumer
               " as this is a potentially harmful command")
517 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
518 c832b6c8 René Nussbaumer
    elif args and opts.show_all:
519 c832b6c8 René Nussbaumer
      ToStderr("Please provide either nodes or use --all, can not use both at"
520 c832b6c8 René Nussbaumer
               " the same time")
521 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
522 c832b6c8 René Nussbaumer
    elif not opts.force and not ConfirmOperation(nodes, "nodes",
523 c832b6c8 René Nussbaumer
                                                 "power %s" % command):
524 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
525 c832b6c8 René Nussbaumer
526 d363797e René Nussbaumer
  opcodelist = []
527 efae0fdd René Nussbaumer
  if not opts.ignore_status and oob_command == constants.OOB_POWER_OFF:
528 c832b6c8 René Nussbaumer
    # TODO: This is a little ugly as we can't catch and revert
529 c832b6c8 René Nussbaumer
    for node in nodes:
530 c832b6c8 René Nussbaumer
      opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True,
531 c832b6c8 René Nussbaumer
                                                auto_promote=opts.auto_promote))
532 d363797e René Nussbaumer
533 c832b6c8 René Nussbaumer
  opcodelist.append(opcodes.OpOobCommand(node_names=nodes,
534 efae0fdd René Nussbaumer
                                         command=oob_command,
535 efae0fdd René Nussbaumer
                                         ignore_status=opts.ignore_status,
536 65a77fab René Nussbaumer
                                         force_master=opts.force_master,
537 65a77fab René Nussbaumer
                                         timeout=opts.oob_timeout))
538 d363797e René Nussbaumer
539 d363797e René Nussbaumer
  cli.SetGenericOpcodeOpts(opcodelist, opts)
540 d363797e René Nussbaumer
541 d363797e René Nussbaumer
  job_id = cli.SendJob(opcodelist)
542 d363797e René Nussbaumer
543 d363797e René Nussbaumer
  # We just want the OOB Opcode status
544 d363797e René Nussbaumer
  # If it fails PollJob gives us the error message in it
545 d363797e René Nussbaumer
  result = cli.PollJob(job_id)[-1]
546 d363797e René Nussbaumer
547 c832b6c8 René Nussbaumer
  errs = 0
548 c832b6c8 René Nussbaumer
  data = []
549 c832b6c8 René Nussbaumer
  for node_result in result:
550 c832b6c8 René Nussbaumer
    (node_tuple, data_tuple) = node_result
551 c832b6c8 René Nussbaumer
    (_, node_name) = node_tuple
552 c832b6c8 René Nussbaumer
    (data_status, data_node) = data_tuple
553 c832b6c8 René Nussbaumer
    if data_status == constants.RS_NORMAL:
554 b04808ea René Nussbaumer
      if oob_command == constants.OOB_POWER_STATUS:
555 c832b6c8 René Nussbaumer
        if data_node[constants.OOB_POWER_STATUS_POWERED]:
556 c832b6c8 René Nussbaumer
          text = "powered"
557 b04808ea René Nussbaumer
        else:
558 c832b6c8 René Nussbaumer
          text = "unpowered"
559 c832b6c8 René Nussbaumer
        data.append([node_name, text])
560 c832b6c8 René Nussbaumer
      else:
561 c832b6c8 René Nussbaumer
        # We don't expect data here, so we just say, it was successfully invoked
562 c832b6c8 René Nussbaumer
        data.append([node_name, "invoked"])
563 c832b6c8 René Nussbaumer
    else:
564 c832b6c8 René Nussbaumer
      errs += 1
565 c832b6c8 René Nussbaumer
      data.append([node_name, cli.FormatResultError(data_status)])
566 c832b6c8 René Nussbaumer
567 c832b6c8 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
568 c832b6c8 René Nussbaumer
                       fields=["node", "status"], data=data)
569 c832b6c8 René Nussbaumer
570 c832b6c8 René Nussbaumer
  for line in data:
571 c832b6c8 René Nussbaumer
    ToStdout(line)
572 abefdcff René Nussbaumer
573 c832b6c8 René Nussbaumer
  if errs:
574 c832b6c8 René Nussbaumer
    return constants.EXIT_FAILURE
575 c832b6c8 René Nussbaumer
  else:
576 c832b6c8 René Nussbaumer
    return constants.EXIT_SUCCESS
577 abefdcff René Nussbaumer
578 abefdcff René Nussbaumer
579 a0724772 René Nussbaumer
def Health(opts, args):
580 a0724772 René Nussbaumer
  """Show health of a node using OOB.
581 a0724772 René Nussbaumer

582 a0724772 René Nussbaumer
  @param opts: the command line options selected by the user
583 a0724772 René Nussbaumer
  @type args: list
584 a0724772 René Nussbaumer
  @param args: should contain only one element, the name of
585 a0724772 René Nussbaumer
      the node to be removed
586 a0724772 René Nussbaumer
  @rtype: int
587 a0724772 René Nussbaumer
  @return: the desired exit code
588 a0724772 René Nussbaumer

589 a0724772 René Nussbaumer
  """
590 65a77fab René Nussbaumer
  op = opcodes.OpOobCommand(node_names=args, command=constants.OOB_HEALTH,
591 65a77fab René Nussbaumer
                            timeout=opts.oob_timeout)
592 a0724772 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
593 a0724772 René Nussbaumer
594 a0724772 René Nussbaumer
  if opts.no_headers:
595 a0724772 René Nussbaumer
    headers = None
596 a0724772 René Nussbaumer
  else:
597 a0724772 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
598 a0724772 René Nussbaumer
599 a0724772 René Nussbaumer
  errs = 0
600 a0724772 René Nussbaumer
  data = []
601 a0724772 René Nussbaumer
  for node_result in result:
602 a0724772 René Nussbaumer
    (node_tuple, data_tuple) = node_result
603 a0724772 René Nussbaumer
    (_, node_name) = node_tuple
604 a0724772 René Nussbaumer
    (data_status, data_node) = data_tuple
605 a0724772 René Nussbaumer
    if data_status == constants.RS_NORMAL:
606 a0724772 René Nussbaumer
      data.append([node_name, "%s=%s" % tuple(data_node[0])])
607 a0724772 René Nussbaumer
      for item, status in data_node[1:]:
608 a0724772 René Nussbaumer
        data.append(["", "%s=%s" % (item, status)])
609 a0724772 René Nussbaumer
    else:
610 a0724772 René Nussbaumer
      errs += 1
611 a0724772 René Nussbaumer
      data.append([node_name, cli.FormatResultError(data_status)])
612 a0724772 René Nussbaumer
613 a0724772 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
614 a0724772 René Nussbaumer
                       fields=["node", "status"], data=data)
615 a0724772 René Nussbaumer
616 a0724772 René Nussbaumer
  for line in data:
617 a0724772 René Nussbaumer
    ToStdout(line)
618 a0724772 René Nussbaumer
619 a0724772 René Nussbaumer
  if errs:
620 a0724772 René Nussbaumer
    return constants.EXIT_FAILURE
621 a0724772 René Nussbaumer
  else:
622 a0724772 René Nussbaumer
    return constants.EXIT_SUCCESS
623 a0724772 René Nussbaumer
624 a0724772 René Nussbaumer
625 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
626 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
627 dcb93971 Michael Hanselmann

628 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
629 ebf366ee Iustin Pop
  @type args: list
630 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
631 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
632 ebf366ee Iustin Pop
      to display data only for those
633 ebf366ee Iustin Pop
  @rtype: int
634 ebf366ee Iustin Pop
  @return: the desired exit code
635 ebf366ee Iustin Pop

636 dcb93971 Michael Hanselmann
  """
637 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
638 dcb93971 Michael Hanselmann
639 8ed55bfd Iustin Pop
  op = opcodes.OpNodeQueryvols(nodes=args, output_fields=selected_fields)
640 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
641 dcb93971 Michael Hanselmann
642 dcb93971 Michael Hanselmann
  if not opts.no_headers:
643 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
644 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
645 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
646 137161c9 Michael Hanselmann
  else:
647 137161c9 Michael Hanselmann
    headers = None
648 137161c9 Michael Hanselmann
649 9fbfbb7b Iustin Pop
  unitfields = ["size"]
650 137161c9 Michael Hanselmann
651 137161c9 Michael Hanselmann
  numfields = ["size"]
652 137161c9 Michael Hanselmann
653 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
654 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
655 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
656 16be8703 Iustin Pop
657 16be8703 Iustin Pop
  for line in data:
658 3a24c527 Iustin Pop
    ToStdout(line)
659 dcb93971 Michael Hanselmann
660 dcb93971 Michael Hanselmann
  return 0
661 dcb93971 Michael Hanselmann
662 dcb93971 Michael Hanselmann
663 9b94905f Iustin Pop
def ListStorage(opts, args):
664 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
665 4007f57d Michael Hanselmann

666 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
667 4007f57d Michael Hanselmann
  @type args: list
668 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
669 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
670 4007f57d Michael Hanselmann
      to display data only for those
671 4007f57d Michael Hanselmann
  @rtype: int
672 4007f57d Michael Hanselmann
  @return: the desired exit code
673 4007f57d Michael Hanselmann

674 4007f57d Michael Hanselmann
  """
675 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
676 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
677 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
678 53548798 Michael Hanselmann
679 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
680 53548798 Michael Hanselmann
681 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
682 4007f57d Michael Hanselmann
683 ad8d0595 Iustin Pop
  op = opcodes.OpNodeQueryStorage(nodes=args,
684 53548798 Michael Hanselmann
                                  storage_type=storage_type,
685 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
686 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
687 4007f57d Michael Hanselmann
688 4007f57d Michael Hanselmann
  if not opts.no_headers:
689 4007f57d Michael Hanselmann
    headers = {
690 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
691 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
692 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
693 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
694 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
695 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
696 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
697 4007f57d Michael Hanselmann
      }
698 4007f57d Michael Hanselmann
  else:
699 4007f57d Michael Hanselmann
    headers = None
700 4007f57d Michael Hanselmann
701 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
702 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
703 4007f57d Michael Hanselmann
704 dc09c3cf Iustin Pop
  # change raw values to nicer strings
705 dc09c3cf Iustin Pop
  for row in output:
706 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
707 dc09c3cf Iustin Pop
      val = row[idx]
708 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
709 dc09c3cf Iustin Pop
        if val:
710 dc09c3cf Iustin Pop
          val = "Y"
711 dc09c3cf Iustin Pop
        else:
712 dc09c3cf Iustin Pop
          val = "N"
713 dc09c3cf Iustin Pop
      row[idx] = str(val)
714 dc09c3cf Iustin Pop
715 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
716 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
717 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
718 4007f57d Michael Hanselmann
719 4007f57d Michael Hanselmann
  for line in data:
720 4007f57d Michael Hanselmann
    ToStdout(line)
721 4007f57d Michael Hanselmann
722 4007f57d Michael Hanselmann
  return 0
723 4007f57d Michael Hanselmann
724 4007f57d Michael Hanselmann
725 9b94905f Iustin Pop
def ModifyStorage(opts, args):
726 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
727 0e89fc2d Michael Hanselmann

728 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
729 0e89fc2d Michael Hanselmann
  @type args: list
730 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
731 0e89fc2d Michael Hanselmann
  @rtype: int
732 0e89fc2d Michael Hanselmann
  @return: the desired exit code
733 0e89fc2d Michael Hanselmann

734 0e89fc2d Michael Hanselmann
  """
735 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
736 0e89fc2d Michael Hanselmann
737 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
738 0e89fc2d Michael Hanselmann
739 0e89fc2d Michael Hanselmann
  changes = {}
740 0e89fc2d Michael Hanselmann
741 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
742 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
743 0e89fc2d Michael Hanselmann
744 0e89fc2d Michael Hanselmann
  if changes:
745 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
746 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
747 0e89fc2d Michael Hanselmann
                                     name=volume_name,
748 0e89fc2d Michael Hanselmann
                                     changes=changes)
749 400ca2f7 Iustin Pop
    SubmitOpCode(op, opts=opts)
750 620a85fd Iustin Pop
  else:
751 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
752 0e89fc2d Michael Hanselmann
753 0e89fc2d Michael Hanselmann
754 9b94905f Iustin Pop
def RepairStorage(opts, args):
755 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
756 1e3463f1 Michael Hanselmann

757 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
758 1e3463f1 Michael Hanselmann
  @type args: list
759 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
760 1e3463f1 Michael Hanselmann
  @rtype: int
761 1e3463f1 Michael Hanselmann
  @return: the desired exit code
762 1e3463f1 Michael Hanselmann

763 1e3463f1 Michael Hanselmann
  """
764 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
765 1e3463f1 Michael Hanselmann
766 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
767 1e3463f1 Michael Hanselmann
768 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
769 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
770 7e9c6a78 Iustin Pop
                                   name=volume_name,
771 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
772 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
773 1e3463f1 Michael Hanselmann
774 1e3463f1 Michael Hanselmann
775 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
776 b31c8676 Iustin Pop
  """Modifies a node.
777 b31c8676 Iustin Pop

778 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
779 b31c8676 Iustin Pop
  @type args: list
780 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
781 b31c8676 Iustin Pop
  @rtype: int
782 b31c8676 Iustin Pop
  @return: the desired exit code
783 b31c8676 Iustin Pop

784 b31c8676 Iustin Pop
  """
785 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
786 4e37f591 René Nussbaumer
                 opts.master_capable, opts.vm_capable, opts.secondary_ip,
787 4e37f591 René Nussbaumer
                 opts.ndparams]
788 53919782 Iustin Pop
  if all_changes.count(None) == len(all_changes):
789 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
790 b31c8676 Iustin Pop
    return 1
791 b31c8676 Iustin Pop
792 f13973c4 Iustin Pop
  op = opcodes.OpNodeSetParams(node_name=args[0],
793 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
794 e7b61bb0 Iustin Pop
                               offline=opts.offline,
795 e7b61bb0 Iustin Pop
                               drained=opts.drained,
796 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
797 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
798 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
799 4c61d894 Iustin Pop
                               force=opts.force,
800 4e37f591 René Nussbaumer
                               ndparams=opts.ndparams,
801 dd94e9f6 René Nussbaumer
                               auto_promote=opts.auto_promote,
802 dd94e9f6 René Nussbaumer
                               powered=opts.node_powered)
803 b31c8676 Iustin Pop
804 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
805 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
806 b31c8676 Iustin Pop
807 b31c8676 Iustin Pop
  if result:
808 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
809 b31c8676 Iustin Pop
    for param, data in result:
810 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
811 b31c8676 Iustin Pop
  return 0
812 b31c8676 Iustin Pop
813 b31c8676 Iustin Pop
814 a8083063 Iustin Pop
commands = {
815 6ea815cf Iustin Pop
  'add': (
816 6ea815cf Iustin Pop
    AddNode, [ArgHost(min=1, max=1)],
817 3ef51126 René Nussbaumer
    [SECONDARY_IP_OPT, READD_OPT, NOSSH_KEYCHECK_OPT, NONODE_SETUP_OPT,
818 fd3d37b6 Iustin Pop
     VERBOSE_OPT, NODEGROUP_OPT, PRIORITY_OPT, CAPAB_MASTER_OPT,
819 4e37f591 René Nussbaumer
     CAPAB_VM_OPT, NODE_PARAMS_OPT],
820 3ef51126 René Nussbaumer
    "[-s ip] [--readd] [--no-ssh-key-check] [--no-node-setup]  [--verbose] "
821 2e6469a1 René Nussbaumer
    " <node_name>",
822 6ea815cf Iustin Pop
    "Add a node to the cluster"),
823 6ea815cf Iustin Pop
  'evacuate': (
824 f8c9fa5c Iustin Pop
    EvacuateNode, [ArgNode(min=1)],
825 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
826 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
827 6ea815cf Iustin Pop
    "[-f] {-I <iallocator> | -n <dst>} <node>",
828 6ea815cf Iustin Pop
    "Relocate the secondary instances from a node"
829 6ea815cf Iustin Pop
    " to other nodes (only for instances with drbd disk template)"),
830 6ea815cf Iustin Pop
  'failover': (
831 aa06f8c6 Michael Hanselmann
    FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT, PRIORITY_OPT],
832 6ea815cf Iustin Pop
    "[-f] <node>",
833 6ea815cf Iustin Pop
    "Stops the primary instances on a node and start them on their"
834 6ea815cf Iustin Pop
    " secondary node (only for instances with drbd disk template)"),
835 6ea815cf Iustin Pop
  'migrate': (
836 aa06f8c6 Michael Hanselmann
    MigrateNode, ARGS_ONE_NODE,
837 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, PRIORITY_OPT],
838 6ea815cf Iustin Pop
    "[-f] <node>",
839 6ea815cf Iustin Pop
    "Migrate all the primary instance on a node away from it"
840 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
841 6ea815cf Iustin Pop
  'info': (
842 064c21f8 Iustin Pop
    ShowNodeConfig, ARGS_MANY_NODES, [],
843 6ea815cf Iustin Pop
    "[<node_name>...]", "Show information about the node(s)"),
844 6ea815cf Iustin Pop
  'list': (
845 6ea815cf Iustin Pop
    ListNodes, ARGS_MANY_NODES,
846 7f5443a0 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT],
847 6ea815cf Iustin Pop
    "[nodes...]",
848 7f5443a0 Michael Hanselmann
    "Lists the nodes in the cluster. The available fields can be shown using"
849 7f5443a0 Michael Hanselmann
    " the \"list-fields\" command (see the man page for details)."
850 7f5443a0 Michael Hanselmann
    " The default field list is (in order): %s." %
851 7f5443a0 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS)),
852 7f5443a0 Michael Hanselmann
  "list-fields": (
853 7f5443a0 Michael Hanselmann
    ListNodeFields, [ArgUnknown()],
854 7f5443a0 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
855 7f5443a0 Michael Hanselmann
    "[fields...]",
856 7f5443a0 Michael Hanselmann
    "Lists all available fields for nodes"),
857 6ea815cf Iustin Pop
  'modify': (
858 6ea815cf Iustin Pop
    SetNodeParams, ARGS_ONE_NODE,
859 53919782 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, MC_OPT, DRAINED_OPT, OFFLINE_OPT,
860 4d32c211 Guido Trotter
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, SECONDARY_IP_OPT,
861 dd94e9f6 René Nussbaumer
     AUTO_PROMOTE_OPT, DRY_RUN_OPT, PRIORITY_OPT, NODE_PARAMS_OPT,
862 dd94e9f6 René Nussbaumer
     NODE_POWERED_OPT],
863 6ea815cf Iustin Pop
    "<node_name>", "Alters the parameters of a node"),
864 6ea815cf Iustin Pop
  'powercycle': (
865 6ea815cf Iustin Pop
    PowercycleNode, ARGS_ONE_NODE,
866 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, CONFIRM_OPT, DRY_RUN_OPT, PRIORITY_OPT],
867 6ea815cf Iustin Pop
    "<node_name>", "Tries to forcefully powercycle a node"),
868 abefdcff René Nussbaumer
  'power': (
869 abefdcff René Nussbaumer
    PowerNode,
870 abefdcff René Nussbaumer
    [ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS),
871 c832b6c8 René Nussbaumer
     ArgNode()],
872 efae0fdd René Nussbaumer
    [SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT, IGNORE_STATUS_OPT,
873 65a77fab René Nussbaumer
     FORCE_MASTER_OPT, FORCE_OPT, NOHDR_OPT, SEP_OPT, ALL_OPT,
874 65a77fab René Nussbaumer
     OOB_TIMEOUT_OPT],
875 c832b6c8 René Nussbaumer
    "on|off|cycle|status [nodes...]",
876 abefdcff René Nussbaumer
    "Change power state of node by calling out-of-band helper."),
877 6ea815cf Iustin Pop
  'remove': (
878 aa06f8c6 Michael Hanselmann
    RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT],
879 6ea815cf Iustin Pop
    "<node_name>", "Removes a node from the cluster"),
880 6ea815cf Iustin Pop
  'volumes': (
881 6ea815cf Iustin Pop
    ListVolumes, [ArgNode()],
882 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, PRIORITY_OPT],
883 6ea815cf Iustin Pop
    "[<node_name>...]", "List logical volumes on node(s)"),
884 9b94905f Iustin Pop
  'list-storage': (
885 9b94905f Iustin Pop
    ListStorage, ARGS_MANY_NODES,
886 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, _STORAGE_TYPE_OPT,
887 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
888 620a85fd Iustin Pop
    "[<node_name>...]", "List physical volumes on node(s). The available"
889 620a85fd Iustin Pop
    " fields are (see the man page for details): %s." %
890 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_STOR_HEADERS))),
891 9b94905f Iustin Pop
  'modify-storage': (
892 9b94905f Iustin Pop
    ModifyStorage,
893 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
894 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_MODIFIABLE_STORAGE_TYPES),
895 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
896 aa06f8c6 Michael Hanselmann
    [ALLOCATABLE_OPT, DRY_RUN_OPT, PRIORITY_OPT],
897 064c21f8 Iustin Pop
    "<node_name> <storage_type> <name>", "Modify storage volume on a node"),
898 9b94905f Iustin Pop
  'repair-storage': (
899 9b94905f Iustin Pop
    RepairStorage,
900 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
901 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_REPAIRABLE_STORAGE_TYPES),
902 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
903 aa06f8c6 Michael Hanselmann
    [IGNORE_CONSIST_OPT, DRY_RUN_OPT, PRIORITY_OPT],
904 6ea815cf Iustin Pop
    "<node_name> <storage_type> <name>",
905 6ea815cf Iustin Pop
    "Repairs a storage volume on a node"),
906 6ea815cf Iustin Pop
  'list-tags': (
907 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_NODE, [],
908 6ea815cf Iustin Pop
    "<node_name>", "List the tags of the given node"),
909 6ea815cf Iustin Pop
  'add-tags': (
910 aa06f8c6 Michael Hanselmann
    AddTags, [ArgNode(min=1, max=1), ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
911 6ea815cf Iustin Pop
    "<node_name> tag...", "Add tags to the given node"),
912 6ea815cf Iustin Pop
  'remove-tags': (
913 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()],
914 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
915 6ea815cf Iustin Pop
    "<node_name> tag...", "Remove tags from the given node"),
916 a0724772 René Nussbaumer
  "health": (
917 a0724772 René Nussbaumer
    Health, ARGS_MANY_NODES,
918 65a77fab René Nussbaumer
    [NOHDR_OPT, SEP_OPT, SUBMIT_OPT, PRIORITY_OPT, OOB_TIMEOUT_OPT],
919 a0724772 René Nussbaumer
    "[<node_name>...]", "List health of node(s) using out-of-band"),
920 a8083063 Iustin Pop
  }
921 a8083063 Iustin Pop
922 a8083063 Iustin Pop
923 37494fa4 Michael Hanselmann
def Main():
924 37494fa4 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_NODE})