Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 42c161cf

History | View | Annotate | Download (28.9 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 65a77fab René Nussbaumer
118 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
119 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
120 86f5eae3 Michael Hanselmann

121 86f5eae3 Michael Hanselmann
  """
122 86f5eae3 Michael Hanselmann
  try:
123 86f5eae3 Michael Hanselmann
    return _USER_STORAGE_TYPE[user_storage_type]
124 86f5eae3 Michael Hanselmann
  except KeyError:
125 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown storage type: %s" % user_storage_type,
126 debac808 Iustin Pop
                               errors.ECODE_INVAL)
127 86f5eae3 Michael Hanselmann
128 86f5eae3 Michael Hanselmann
129 2e6469a1 René Nussbaumer
def _RunSetupSSH(options, nodes):
130 2e6469a1 René Nussbaumer
  """Wrapper around utils.RunCmd to call setup-ssh
131 2e6469a1 René Nussbaumer

132 2e6469a1 René Nussbaumer
  @param options: The command line options
133 2e6469a1 René Nussbaumer
  @param nodes: The nodes to setup
134 2e6469a1 René Nussbaumer

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

163 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
164 ebf366ee Iustin Pop
  @type args: list
165 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
166 ebf366ee Iustin Pop
  @rtype: int
167 ebf366ee Iustin Pop
  @return: the desired exit code
168 05ccd983 Guido Trotter

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

575 a0724772 René Nussbaumer
  @param opts: the command line options selected by the user
576 a0724772 René Nussbaumer
  @type args: list
577 a0724772 René Nussbaumer
  @param args: should contain only one element, the name of
578 a0724772 René Nussbaumer
      the node to be removed
579 a0724772 René Nussbaumer
  @rtype: int
580 a0724772 René Nussbaumer
  @return: the desired exit code
581 a0724772 René Nussbaumer

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

621 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
622 ebf366ee Iustin Pop
  @type args: list
623 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
624 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
625 ebf366ee Iustin Pop
      to display data only for those
626 ebf366ee Iustin Pop
  @rtype: int
627 ebf366ee Iustin Pop
  @return: the desired exit code
628 ebf366ee Iustin Pop

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

659 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
660 4007f57d Michael Hanselmann
  @type args: list
661 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
662 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
663 4007f57d Michael Hanselmann
      to display data only for those
664 4007f57d Michael Hanselmann
  @rtype: int
665 4007f57d Michael Hanselmann
  @return: the desired exit code
666 4007f57d Michael Hanselmann

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

721 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
722 0e89fc2d Michael Hanselmann
  @type args: list
723 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
724 0e89fc2d Michael Hanselmann
  @rtype: int
725 0e89fc2d Michael Hanselmann
  @return: the desired exit code
726 0e89fc2d Michael Hanselmann

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

750 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
751 1e3463f1 Michael Hanselmann
  @type args: list
752 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
753 1e3463f1 Michael Hanselmann
  @rtype: int
754 1e3463f1 Michael Hanselmann
  @return: the desired exit code
755 1e3463f1 Michael Hanselmann

756 1e3463f1 Michael Hanselmann
  """
757 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
758 1e3463f1 Michael Hanselmann
759 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
760 1e3463f1 Michael Hanselmann
761 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
762 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
763 7e9c6a78 Iustin Pop
                                   name=volume_name,
764 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
765 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
766 1e3463f1 Michael Hanselmann
767 1e3463f1 Michael Hanselmann
768 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
769 b31c8676 Iustin Pop
  """Modifies a node.
770 b31c8676 Iustin Pop

771 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
772 b31c8676 Iustin Pop
  @type args: list
773 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
774 b31c8676 Iustin Pop
  @rtype: int
775 b31c8676 Iustin Pop
  @return: the desired exit code
776 b31c8676 Iustin Pop

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