Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 3ad56046

History | View | Annotate | Download (30.1 kB)

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

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

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

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

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

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

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

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

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

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

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

267 a5bc662a Iustin Pop
  """
268 aafee533 Michael Hanselmann
  if opts.dst_node is not None:
269 aafee533 Michael Hanselmann
    ToStderr("New secondary node given (disabling iallocator), hence evacuating"
270 aafee533 Michael Hanselmann
             " secondary instances only.")
271 aafee533 Michael Hanselmann
    opts.secondary_only = True
272 aafee533 Michael Hanselmann
    opts.primary_only = False
273 aafee533 Michael Hanselmann
274 aafee533 Michael Hanselmann
  if opts.secondary_only and opts.primary_only:
275 aafee533 Michael Hanselmann
    raise errors.OpPrereqError("Only one of the --primary-only and"
276 aafee533 Michael Hanselmann
                               " --secondary-only options can be passed",
277 aafee533 Michael Hanselmann
                               errors.ECODE_INVAL)
278 aafee533 Michael Hanselmann
  elif opts.primary_only:
279 aafee533 Michael Hanselmann
    mode = constants.IALLOCATOR_NEVAC_PRI
280 aafee533 Michael Hanselmann
  elif opts.secondary_only:
281 aafee533 Michael Hanselmann
    mode = constants.IALLOCATOR_NEVAC_SEC
282 aafee533 Michael Hanselmann
  else:
283 aafee533 Michael Hanselmann
    mode = constants.IALLOCATOR_NEVAC_ALL
284 c4ed32cb Iustin Pop
285 aafee533 Michael Hanselmann
  # Determine affected instances
286 aafee533 Michael Hanselmann
  fields = []
287 c4ed32cb Iustin Pop
288 aafee533 Michael Hanselmann
  if not opts.secondary_only:
289 aafee533 Michael Hanselmann
    fields.append("pinst_list")
290 aafee533 Michael Hanselmann
  if not opts.primary_only:
291 aafee533 Michael Hanselmann
    fields.append("sinst_list")
292 f8c9fa5c Iustin Pop
293 aafee533 Michael Hanselmann
  cl = GetClient()
294 aafee533 Michael Hanselmann
295 aafee533 Michael Hanselmann
  result = cl.QueryNodes(names=args, fields=fields, use_locking=False)
296 aafee533 Michael Hanselmann
  instances = set(itertools.chain(*itertools.chain(*itertools.chain(result))))
297 aafee533 Michael Hanselmann
298 aafee533 Michael Hanselmann
  if not instances:
299 aafee533 Michael Hanselmann
    # No instances to evacuate
300 aafee533 Michael Hanselmann
    ToStderr("No instances to evacuate on node(s) %s, exiting.",
301 f8c9fa5c Iustin Pop
             utils.CommaJoin(args))
302 a5bc662a Iustin Pop
    return constants.EXIT_SUCCESS
303 a5bc662a Iustin Pop
304 aafee533 Michael Hanselmann
  if not (opts.force or
305 aafee533 Michael Hanselmann
          AskUser("Relocate instance(s) %s from node(s) %s?" %
306 aafee533 Michael Hanselmann
                  (utils.CommaJoin(utils.NiceSort(instances)),
307 aafee533 Michael Hanselmann
                   utils.CommaJoin(args)))):
308 a5bc662a Iustin Pop
    return constants.EXIT_CONFIRMATION
309 a5bc662a Iustin Pop
310 aafee533 Michael Hanselmann
  # Evacuate node
311 aafee533 Michael Hanselmann
  op = opcodes.OpNodeEvacuate(node_name=args[0], mode=mode,
312 aafee533 Michael Hanselmann
                              remote_node=opts.dst_node,
313 aafee533 Michael Hanselmann
                              iallocator=opts.iallocator,
314 aafee533 Michael Hanselmann
                              early_release=opts.early_release)
315 aafee533 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
316 aafee533 Michael Hanselmann
317 aafee533 Michael Hanselmann
  # Keep track of submitted jobs
318 f8c9fa5c Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
319 aafee533 Michael Hanselmann
320 aafee533 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
321 aafee533 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
322 aafee533 Michael Hanselmann
323 f8c9fa5c Iustin Pop
  results = jex.GetResults()
324 f8c9fa5c Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
325 f8c9fa5c Iustin Pop
  if bad_cnt == 0:
326 aafee533 Michael Hanselmann
    ToStdout("All instances evacuated successfully.")
327 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_SUCCESS
328 f8c9fa5c Iustin Pop
  else:
329 aafee533 Michael Hanselmann
    ToStdout("There were %s errors during the evacuation.", bad_cnt)
330 f8c9fa5c Iustin Pop
    rcode = constants.EXIT_FAILURE
331 aafee533 Michael Hanselmann
332 f8c9fa5c Iustin Pop
  return rcode
333 a5bc662a Iustin Pop
334 a5bc662a Iustin Pop
335 c450e9b0 Iustin Pop
def FailoverNode(opts, args):
336 c450e9b0 Iustin Pop
  """Failover all primary instance on a node.
337 c450e9b0 Iustin Pop

338 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
339 ebf366ee Iustin Pop
  @type args: list
340 ebf366ee Iustin Pop
  @param args: should be an empty list
341 ebf366ee Iustin Pop
  @rtype: int
342 ebf366ee Iustin Pop
  @return: the desired exit code
343 ebf366ee Iustin Pop

344 c450e9b0 Iustin Pop
  """
345 479636a3 Iustin Pop
  cl = GetClient()
346 c450e9b0 Iustin Pop
  force = opts.force
347 c450e9b0 Iustin Pop
  selected_fields = ["name", "pinst_list"]
348 c450e9b0 Iustin Pop
349 2e7b8369 Iustin Pop
  # these fields are static data anyway, so it doesn't matter, but
350 2e7b8369 Iustin Pop
  # locking=True should be safer
351 2e7b8369 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields,
352 77921a95 Iustin Pop
                         use_locking=False)
353 c450e9b0 Iustin Pop
  node, pinst = result[0]
354 c450e9b0 Iustin Pop
355 c450e9b0 Iustin Pop
  if not pinst:
356 3a24c527 Iustin Pop
    ToStderr("No primary instances on node %s, exiting.", node)
357 c450e9b0 Iustin Pop
    return 0
358 c450e9b0 Iustin Pop
359 c450e9b0 Iustin Pop
  pinst = utils.NiceSort(pinst)
360 c450e9b0 Iustin Pop
361 c450e9b0 Iustin Pop
  retcode = 0
362 c450e9b0 Iustin Pop
363 c450e9b0 Iustin Pop
  if not force and not AskUser("Fail over instance(s) %s?" %
364 c450e9b0 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
365 c450e9b0 Iustin Pop
    return 2
366 c450e9b0 Iustin Pop
367 cb573a31 Iustin Pop
  jex = JobExecutor(cl=cl, opts=opts)
368 c450e9b0 Iustin Pop
  for iname in pinst:
369 019dbee1 Iustin Pop
    op = opcodes.OpInstanceFailover(instance_name=iname,
370 1b7761fd Apollon Oikonomopoulos
                                    ignore_consistency=opts.ignore_consistency,
371 1b7761fd Apollon Oikonomopoulos
                                    iallocator=opts.iallocator)
372 479636a3 Iustin Pop
    jex.QueueJob(iname, op)
373 479636a3 Iustin Pop
  results = jex.GetResults()
374 479636a3 Iustin Pop
  bad_cnt = len([row for row in results if not row[0]])
375 479636a3 Iustin Pop
  if bad_cnt == 0:
376 479636a3 Iustin Pop
    ToStdout("All %d instance(s) failed over successfully.", len(results))
377 c450e9b0 Iustin Pop
  else:
378 3a24c527 Iustin Pop
    ToStdout("There were errors during the failover:\n"
379 479636a3 Iustin Pop
             "%d error(s) out of %d instance(s).", bad_cnt, len(results))
380 c450e9b0 Iustin Pop
  return retcode
381 c450e9b0 Iustin Pop
382 c450e9b0 Iustin Pop
383 40ef0ed6 Iustin Pop
def MigrateNode(opts, args):
384 40ef0ed6 Iustin Pop
  """Migrate all primary instance on a node.
385 40ef0ed6 Iustin Pop

386 40ef0ed6 Iustin Pop
  """
387 40ef0ed6 Iustin Pop
  cl = GetClient()
388 40ef0ed6 Iustin Pop
  force = opts.force
389 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
390 40ef0ed6 Iustin Pop
391 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
392 b7a1c816 Michael Hanselmann
  ((node, pinst), ) = result
393 40ef0ed6 Iustin Pop
394 40ef0ed6 Iustin Pop
  if not pinst:
395 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
396 40ef0ed6 Iustin Pop
    return 0
397 40ef0ed6 Iustin Pop
398 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
399 40ef0ed6 Iustin Pop
400 b7a1c816 Michael Hanselmann
  if not (force or
401 b7a1c816 Michael Hanselmann
          AskUser("Migrate instance(s) %s?" %
402 b7a1c816 Michael Hanselmann
                  utils.CommaJoin(utils.NiceSort(pinst)))):
403 b7a1c816 Michael Hanselmann
    return constants.EXIT_CONFIRMATION
404 40ef0ed6 Iustin Pop
405 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
406 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
407 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
408 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
409 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
410 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
411 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
412 e71b9ef4 Iustin Pop
  else:
413 8c35561f Iustin Pop
    mode = opts.migration_mode
414 b7a1c816 Michael Hanselmann
415 1b7761fd Apollon Oikonomopoulos
  op = opcodes.OpNodeMigrate(node_name=args[0], mode=mode,
416 f8fa4175 Michael Hanselmann
                             iallocator=opts.iallocator,
417 f8fa4175 Michael Hanselmann
                             target_node=opts.dst_node)
418 b7a1c816 Michael Hanselmann
419 b7a1c816 Michael Hanselmann
  result = SubmitOpCode(op, cl=cl, opts=opts)
420 b7a1c816 Michael Hanselmann
421 b7a1c816 Michael Hanselmann
  # Keep track of submitted jobs
422 b7a1c816 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
423 b7a1c816 Michael Hanselmann
424 b7a1c816 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
425 b7a1c816 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
426 b7a1c816 Michael Hanselmann
427 b7a1c816 Michael Hanselmann
  results = jex.GetResults()
428 b7a1c816 Michael Hanselmann
  bad_cnt = len([row for row in results if not row[0]])
429 b7a1c816 Michael Hanselmann
  if bad_cnt == 0:
430 b7a1c816 Michael Hanselmann
    ToStdout("All instances migrated successfully.")
431 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
432 b7a1c816 Michael Hanselmann
  else:
433 b7a1c816 Michael Hanselmann
    ToStdout("There were %s errors during the node migration.", bad_cnt)
434 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
435 b7a1c816 Michael Hanselmann
436 b7a1c816 Michael Hanselmann
  return rcode
437 40ef0ed6 Iustin Pop
438 40ef0ed6 Iustin Pop
439 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
440 a8083063 Iustin Pop
  """Show node information.
441 a8083063 Iustin Pop

442 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
443 ebf366ee Iustin Pop
  @type args: list
444 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
445 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
446 ebf366ee Iustin Pop
      a list of nodes to be queried for information
447 ebf366ee Iustin Pop
  @rtype: int
448 ebf366ee Iustin Pop
  @return: the desired exit code
449 ebf366ee Iustin Pop

450 a8083063 Iustin Pop
  """
451 2e7b8369 Iustin Pop
  cl = GetClient()
452 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
453 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
454 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
455 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
456 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
457 77921a95 Iustin Pop
                         names=args, use_locking=False)
458 a8083063 Iustin Pop
459 8572f1fe René Nussbaumer
  for (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
460 8572f1fe René Nussbaumer
       master_capable, vm_capable, powered, ndparams,
461 8572f1fe René Nussbaumer
       ndparams_custom) in result:
462 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
463 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
464 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
465 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
466 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
467 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
468 016acd85 René Nussbaumer
    if powered is not None:
469 016acd85 René Nussbaumer
      ToStdout("  powered: %s", powered)
470 7b4978ad Iustin Pop
    ToStdout("  master_capable: %s", master_capable)
471 7b4978ad Iustin Pop
    ToStdout("  vm_capable: %s", vm_capable)
472 7b4978ad Iustin Pop
    if vm_capable:
473 7b4978ad Iustin Pop
      if pinst:
474 7b4978ad Iustin Pop
        ToStdout("  primary for instances:")
475 7b4978ad Iustin Pop
        for iname in utils.NiceSort(pinst):
476 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
477 7b4978ad Iustin Pop
      else:
478 7b4978ad Iustin Pop
        ToStdout("  primary for no instances")
479 7b4978ad Iustin Pop
      if sinst:
480 7b4978ad Iustin Pop
        ToStdout("  secondary for instances:")
481 7b4978ad Iustin Pop
        for iname in utils.NiceSort(sinst):
482 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
483 7b4978ad Iustin Pop
      else:
484 7b4978ad Iustin Pop
        ToStdout("  secondary for no instances")
485 8572f1fe René Nussbaumer
    ToStdout("  node parameters:")
486 8572f1fe René Nussbaumer
    buf = StringIO()
487 8572f1fe René Nussbaumer
    FormatParameterDict(buf, ndparams_custom, ndparams, level=2)
488 8572f1fe René Nussbaumer
    ToStdout(buf.getvalue().rstrip("\n"))
489 a8083063 Iustin Pop
490 a8083063 Iustin Pop
  return 0
491 a8083063 Iustin Pop
492 a8083063 Iustin Pop
493 a8083063 Iustin Pop
def RemoveNode(opts, args):
494 ebf366ee Iustin Pop
  """Remove a node from the cluster.
495 ebf366ee Iustin Pop

496 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
497 ebf366ee Iustin Pop
  @type args: list
498 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
499 ebf366ee Iustin Pop
      the node to be removed
500 ebf366ee Iustin Pop
  @rtype: int
501 ebf366ee Iustin Pop
  @return: the desired exit code
502 ebf366ee Iustin Pop

503 ebf366ee Iustin Pop
  """
504 73d565a3 Iustin Pop
  op = opcodes.OpNodeRemove(node_name=args[0])
505 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
506 ebf366ee Iustin Pop
  return 0
507 a8083063 Iustin Pop
508 a8083063 Iustin Pop
509 f5118ade Iustin Pop
def PowercycleNode(opts, args):
510 f5118ade Iustin Pop
  """Remove a node from the cluster.
511 f5118ade Iustin Pop

512 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
513 f5118ade Iustin Pop
  @type args: list
514 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
515 f5118ade Iustin Pop
      the node to be removed
516 f5118ade Iustin Pop
  @rtype: int
517 f5118ade Iustin Pop
  @return: the desired exit code
518 f5118ade Iustin Pop

519 f5118ade Iustin Pop
  """
520 f5118ade Iustin Pop
  node = args[0]
521 f5118ade Iustin Pop
  if (not opts.confirm and
522 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
523 f5118ade Iustin Pop
    return 2
524 f5118ade Iustin Pop
525 e0d4735f Iustin Pop
  op = opcodes.OpNodePowercycle(node_name=node, force=opts.force)
526 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
527 48418fea Iustin Pop
  if result:
528 48418fea Iustin Pop
    ToStderr(result)
529 f5118ade Iustin Pop
  return 0
530 f5118ade Iustin Pop
531 f5118ade Iustin Pop
532 abefdcff René Nussbaumer
def PowerNode(opts, args):
533 abefdcff René Nussbaumer
  """Change/ask power state of a node.
534 abefdcff René Nussbaumer

535 abefdcff René Nussbaumer
  @param opts: the command line options selected by the user
536 abefdcff René Nussbaumer
  @type args: list
537 abefdcff René Nussbaumer
  @param args: should contain only one element, the name of
538 abefdcff René Nussbaumer
      the node to be removed
539 abefdcff René Nussbaumer
  @rtype: int
540 abefdcff René Nussbaumer
  @return: the desired exit code
541 abefdcff René Nussbaumer

542 abefdcff René Nussbaumer
  """
543 c832b6c8 René Nussbaumer
  command = args.pop(0)
544 c832b6c8 René Nussbaumer
545 c832b6c8 René Nussbaumer
  if opts.no_headers:
546 c832b6c8 René Nussbaumer
    headers = None
547 c832b6c8 René Nussbaumer
  else:
548 c832b6c8 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
549 abefdcff René Nussbaumer
550 abefdcff René Nussbaumer
  if command not in _LIST_POWER_COMMANDS:
551 abefdcff René Nussbaumer
    ToStderr("power subcommand %s not supported." % command)
552 abefdcff René Nussbaumer
    return constants.EXIT_FAILURE
553 abefdcff René Nussbaumer
554 abefdcff René Nussbaumer
  oob_command = "power-%s" % command
555 abefdcff René Nussbaumer
556 c832b6c8 René Nussbaumer
  if oob_command in _OOB_COMMAND_ASK:
557 fed67843 René Nussbaumer
    if not args:
558 fed67843 René Nussbaumer
      ToStderr("Please provide at least one node for this command")
559 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
560 fed67843 René Nussbaumer
    elif not opts.force and not ConfirmOperation(args, "nodes",
561 c832b6c8 René Nussbaumer
                                                 "power %s" % command):
562 c832b6c8 René Nussbaumer
      return constants.EXIT_FAILURE
563 fed67843 René Nussbaumer
    assert len(args) > 0
564 c832b6c8 René Nussbaumer
565 d363797e René Nussbaumer
  opcodelist = []
566 efae0fdd René Nussbaumer
  if not opts.ignore_status and oob_command == constants.OOB_POWER_OFF:
567 c832b6c8 René Nussbaumer
    # TODO: This is a little ugly as we can't catch and revert
568 fed67843 René Nussbaumer
    for node in args:
569 c832b6c8 René Nussbaumer
      opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True,
570 c832b6c8 René Nussbaumer
                                                auto_promote=opts.auto_promote))
571 d363797e René Nussbaumer
572 fed67843 René Nussbaumer
  opcodelist.append(opcodes.OpOobCommand(node_names=args,
573 efae0fdd René Nussbaumer
                                         command=oob_command,
574 efae0fdd René Nussbaumer
                                         ignore_status=opts.ignore_status,
575 0a1fc31c René Nussbaumer
                                         timeout=opts.oob_timeout,
576 0a1fc31c René Nussbaumer
                                         power_delay=opts.power_delay))
577 d363797e René Nussbaumer
578 d363797e René Nussbaumer
  cli.SetGenericOpcodeOpts(opcodelist, opts)
579 d363797e René Nussbaumer
580 d363797e René Nussbaumer
  job_id = cli.SendJob(opcodelist)
581 d363797e René Nussbaumer
582 d363797e René Nussbaumer
  # We just want the OOB Opcode status
583 d363797e René Nussbaumer
  # If it fails PollJob gives us the error message in it
584 d363797e René Nussbaumer
  result = cli.PollJob(job_id)[-1]
585 d363797e René Nussbaumer
586 c832b6c8 René Nussbaumer
  errs = 0
587 c832b6c8 René Nussbaumer
  data = []
588 c832b6c8 René Nussbaumer
  for node_result in result:
589 c832b6c8 René Nussbaumer
    (node_tuple, data_tuple) = node_result
590 c832b6c8 René Nussbaumer
    (_, node_name) = node_tuple
591 c832b6c8 René Nussbaumer
    (data_status, data_node) = data_tuple
592 c832b6c8 René Nussbaumer
    if data_status == constants.RS_NORMAL:
593 b04808ea René Nussbaumer
      if oob_command == constants.OOB_POWER_STATUS:
594 c832b6c8 René Nussbaumer
        if data_node[constants.OOB_POWER_STATUS_POWERED]:
595 c832b6c8 René Nussbaumer
          text = "powered"
596 b04808ea René Nussbaumer
        else:
597 c832b6c8 René Nussbaumer
          text = "unpowered"
598 c832b6c8 René Nussbaumer
        data.append([node_name, text])
599 c832b6c8 René Nussbaumer
      else:
600 c832b6c8 René Nussbaumer
        # We don't expect data here, so we just say, it was successfully invoked
601 c832b6c8 René Nussbaumer
        data.append([node_name, "invoked"])
602 c832b6c8 René Nussbaumer
    else:
603 c832b6c8 René Nussbaumer
      errs += 1
604 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
605 c832b6c8 René Nussbaumer
606 c832b6c8 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
607 c832b6c8 René Nussbaumer
                       fields=["node", "status"], data=data)
608 c832b6c8 René Nussbaumer
609 c832b6c8 René Nussbaumer
  for line in data:
610 c832b6c8 René Nussbaumer
    ToStdout(line)
611 abefdcff René Nussbaumer
612 c832b6c8 René Nussbaumer
  if errs:
613 c832b6c8 René Nussbaumer
    return constants.EXIT_FAILURE
614 c832b6c8 René Nussbaumer
  else:
615 c832b6c8 René Nussbaumer
    return constants.EXIT_SUCCESS
616 abefdcff René Nussbaumer
617 abefdcff René Nussbaumer
618 a0724772 René Nussbaumer
def Health(opts, args):
619 a0724772 René Nussbaumer
  """Show health of a node using OOB.
620 a0724772 René Nussbaumer

621 a0724772 René Nussbaumer
  @param opts: the command line options selected by the user
622 a0724772 René Nussbaumer
  @type args: list
623 a0724772 René Nussbaumer
  @param args: should contain only one element, the name of
624 a0724772 René Nussbaumer
      the node to be removed
625 a0724772 René Nussbaumer
  @rtype: int
626 a0724772 René Nussbaumer
  @return: the desired exit code
627 a0724772 René Nussbaumer

628 a0724772 René Nussbaumer
  """
629 65a77fab René Nussbaumer
  op = opcodes.OpOobCommand(node_names=args, command=constants.OOB_HEALTH,
630 65a77fab René Nussbaumer
                            timeout=opts.oob_timeout)
631 a0724772 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
632 a0724772 René Nussbaumer
633 a0724772 René Nussbaumer
  if opts.no_headers:
634 a0724772 René Nussbaumer
    headers = None
635 a0724772 René Nussbaumer
  else:
636 a0724772 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
637 a0724772 René Nussbaumer
638 a0724772 René Nussbaumer
  errs = 0
639 a0724772 René Nussbaumer
  data = []
640 a0724772 René Nussbaumer
  for node_result in result:
641 a0724772 René Nussbaumer
    (node_tuple, data_tuple) = node_result
642 a0724772 René Nussbaumer
    (_, node_name) = node_tuple
643 a0724772 René Nussbaumer
    (data_status, data_node) = data_tuple
644 a0724772 René Nussbaumer
    if data_status == constants.RS_NORMAL:
645 a0724772 René Nussbaumer
      data.append([node_name, "%s=%s" % tuple(data_node[0])])
646 a0724772 René Nussbaumer
      for item, status in data_node[1:]:
647 a0724772 René Nussbaumer
        data.append(["", "%s=%s" % (item, status)])
648 a0724772 René Nussbaumer
    else:
649 a0724772 René Nussbaumer
      errs += 1
650 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
651 a0724772 René Nussbaumer
652 a0724772 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
653 a0724772 René Nussbaumer
                       fields=["node", "status"], data=data)
654 a0724772 René Nussbaumer
655 a0724772 René Nussbaumer
  for line in data:
656 a0724772 René Nussbaumer
    ToStdout(line)
657 a0724772 René Nussbaumer
658 a0724772 René Nussbaumer
  if errs:
659 a0724772 René Nussbaumer
    return constants.EXIT_FAILURE
660 a0724772 René Nussbaumer
  else:
661 a0724772 René Nussbaumer
    return constants.EXIT_SUCCESS
662 a0724772 René Nussbaumer
663 a0724772 René Nussbaumer
664 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
665 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
666 dcb93971 Michael Hanselmann

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

675 dcb93971 Michael Hanselmann
  """
676 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
677 dcb93971 Michael Hanselmann
678 8ed55bfd Iustin Pop
  op = opcodes.OpNodeQueryvols(nodes=args, output_fields=selected_fields)
679 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
680 dcb93971 Michael Hanselmann
681 dcb93971 Michael Hanselmann
  if not opts.no_headers:
682 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
683 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
684 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
685 137161c9 Michael Hanselmann
  else:
686 137161c9 Michael Hanselmann
    headers = None
687 137161c9 Michael Hanselmann
688 9fbfbb7b Iustin Pop
  unitfields = ["size"]
689 137161c9 Michael Hanselmann
690 137161c9 Michael Hanselmann
  numfields = ["size"]
691 137161c9 Michael Hanselmann
692 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
693 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
694 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
695 16be8703 Iustin Pop
696 16be8703 Iustin Pop
  for line in data:
697 3a24c527 Iustin Pop
    ToStdout(line)
698 dcb93971 Michael Hanselmann
699 dcb93971 Michael Hanselmann
  return 0
700 dcb93971 Michael Hanselmann
701 dcb93971 Michael Hanselmann
702 9b94905f Iustin Pop
def ListStorage(opts, args):
703 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
704 4007f57d Michael Hanselmann

705 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
706 4007f57d Michael Hanselmann
  @type args: list
707 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
708 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
709 4007f57d Michael Hanselmann
      to display data only for those
710 4007f57d Michael Hanselmann
  @rtype: int
711 4007f57d Michael Hanselmann
  @return: the desired exit code
712 4007f57d Michael Hanselmann

713 4007f57d Michael Hanselmann
  """
714 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
715 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
716 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
717 53548798 Michael Hanselmann
718 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
719 53548798 Michael Hanselmann
720 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
721 4007f57d Michael Hanselmann
722 ad8d0595 Iustin Pop
  op = opcodes.OpNodeQueryStorage(nodes=args,
723 53548798 Michael Hanselmann
                                  storage_type=storage_type,
724 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
725 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
726 4007f57d Michael Hanselmann
727 4007f57d Michael Hanselmann
  if not opts.no_headers:
728 4007f57d Michael Hanselmann
    headers = {
729 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
730 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
731 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
732 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
733 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
734 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
735 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
736 4007f57d Michael Hanselmann
      }
737 4007f57d Michael Hanselmann
  else:
738 4007f57d Michael Hanselmann
    headers = None
739 4007f57d Michael Hanselmann
740 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
741 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
742 4007f57d Michael Hanselmann
743 dc09c3cf Iustin Pop
  # change raw values to nicer strings
744 dc09c3cf Iustin Pop
  for row in output:
745 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
746 dc09c3cf Iustin Pop
      val = row[idx]
747 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
748 dc09c3cf Iustin Pop
        if val:
749 dc09c3cf Iustin Pop
          val = "Y"
750 dc09c3cf Iustin Pop
        else:
751 dc09c3cf Iustin Pop
          val = "N"
752 dc09c3cf Iustin Pop
      row[idx] = str(val)
753 dc09c3cf Iustin Pop
754 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
755 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
756 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
757 4007f57d Michael Hanselmann
758 4007f57d Michael Hanselmann
  for line in data:
759 4007f57d Michael Hanselmann
    ToStdout(line)
760 4007f57d Michael Hanselmann
761 4007f57d Michael Hanselmann
  return 0
762 4007f57d Michael Hanselmann
763 4007f57d Michael Hanselmann
764 9b94905f Iustin Pop
def ModifyStorage(opts, args):
765 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
766 0e89fc2d Michael Hanselmann

767 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
768 0e89fc2d Michael Hanselmann
  @type args: list
769 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
770 0e89fc2d Michael Hanselmann
  @rtype: int
771 0e89fc2d Michael Hanselmann
  @return: the desired exit code
772 0e89fc2d Michael Hanselmann

773 0e89fc2d Michael Hanselmann
  """
774 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
775 0e89fc2d Michael Hanselmann
776 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
777 0e89fc2d Michael Hanselmann
778 0e89fc2d Michael Hanselmann
  changes = {}
779 0e89fc2d Michael Hanselmann
780 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
781 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
782 0e89fc2d Michael Hanselmann
783 0e89fc2d Michael Hanselmann
  if changes:
784 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
785 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
786 0e89fc2d Michael Hanselmann
                                     name=volume_name,
787 0e89fc2d Michael Hanselmann
                                     changes=changes)
788 400ca2f7 Iustin Pop
    SubmitOpCode(op, opts=opts)
789 620a85fd Iustin Pop
  else:
790 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
791 0e89fc2d Michael Hanselmann
792 0e89fc2d Michael Hanselmann
793 9b94905f Iustin Pop
def RepairStorage(opts, args):
794 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
795 1e3463f1 Michael Hanselmann

796 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
797 1e3463f1 Michael Hanselmann
  @type args: list
798 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
799 1e3463f1 Michael Hanselmann
  @rtype: int
800 1e3463f1 Michael Hanselmann
  @return: the desired exit code
801 1e3463f1 Michael Hanselmann

802 1e3463f1 Michael Hanselmann
  """
803 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
804 1e3463f1 Michael Hanselmann
805 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
806 1e3463f1 Michael Hanselmann
807 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
808 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
809 7e9c6a78 Iustin Pop
                                   name=volume_name,
810 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
811 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
812 1e3463f1 Michael Hanselmann
813 1e3463f1 Michael Hanselmann
814 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
815 b31c8676 Iustin Pop
  """Modifies a node.
816 b31c8676 Iustin Pop

817 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
818 b31c8676 Iustin Pop
  @type args: list
819 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
820 b31c8676 Iustin Pop
  @rtype: int
821 b31c8676 Iustin Pop
  @return: the desired exit code
822 b31c8676 Iustin Pop

823 b31c8676 Iustin Pop
  """
824 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
825 4e37f591 René Nussbaumer
                 opts.master_capable, opts.vm_capable, opts.secondary_ip,
826 4e37f591 René Nussbaumer
                 opts.ndparams]
827 53919782 Iustin Pop
  if all_changes.count(None) == len(all_changes):
828 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
829 b31c8676 Iustin Pop
    return 1
830 b31c8676 Iustin Pop
831 f13973c4 Iustin Pop
  op = opcodes.OpNodeSetParams(node_name=args[0],
832 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
833 e7b61bb0 Iustin Pop
                               offline=opts.offline,
834 e7b61bb0 Iustin Pop
                               drained=opts.drained,
835 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
836 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
837 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
838 4c61d894 Iustin Pop
                               force=opts.force,
839 4e37f591 René Nussbaumer
                               ndparams=opts.ndparams,
840 dd94e9f6 René Nussbaumer
                               auto_promote=opts.auto_promote,
841 dd94e9f6 René Nussbaumer
                               powered=opts.node_powered)
842 b31c8676 Iustin Pop
843 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
844 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
845 b31c8676 Iustin Pop
846 b31c8676 Iustin Pop
  if result:
847 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
848 b31c8676 Iustin Pop
    for param, data in result:
849 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
850 b31c8676 Iustin Pop
  return 0
851 b31c8676 Iustin Pop
852 b31c8676 Iustin Pop
853 a8083063 Iustin Pop
commands = {
854 d0c8c01d Iustin Pop
  "add": (
855 6ea815cf Iustin Pop
    AddNode, [ArgHost(min=1, max=1)],
856 61413377 Stephen Shirley
    [SECONDARY_IP_OPT, READD_OPT, NOSSH_KEYCHECK_OPT, NODE_FORCE_JOIN_OPT,
857 61413377 Stephen Shirley
     NONODE_SETUP_OPT, VERBOSE_OPT, NODEGROUP_OPT, PRIORITY_OPT,
858 61413377 Stephen Shirley
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, NODE_PARAMS_OPT],
859 61413377 Stephen Shirley
    "[-s ip] [--readd] [--no-ssh-key-check] [--force-join]"
860 61413377 Stephen Shirley
    " [--no-node-setup] [--verbose]"
861 2e6469a1 René Nussbaumer
    " <node_name>",
862 6ea815cf Iustin Pop
    "Add a node to the cluster"),
863 aafee533 Michael Hanselmann
  "evacuate": (
864 aafee533 Michael Hanselmann
    EvacuateNode, ARGS_ONE_NODE,
865 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
866 aafee533 Michael Hanselmann
     PRIORITY_OPT, PRIMARY_ONLY_OPT, SECONDARY_ONLY_OPT],
867 6ea815cf Iustin Pop
    "[-f] {-I <iallocator> | -n <dst>} <node>",
868 f1dff7ec Iustin Pop
    "Relocate the primary and/or secondary instances from a node"),
869 d0c8c01d Iustin Pop
  "failover": (
870 1b7761fd Apollon Oikonomopoulos
    FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT,
871 1b7761fd Apollon Oikonomopoulos
                                  IALLOCATOR_OPT, PRIORITY_OPT],
872 6ea815cf Iustin Pop
    "[-f] <node>",
873 6ea815cf Iustin Pop
    "Stops the primary instances on a node and start them on their"
874 6ea815cf Iustin Pop
    " secondary node (only for instances with drbd disk template)"),
875 d0c8c01d Iustin Pop
  "migrate": (
876 aa06f8c6 Michael Hanselmann
    MigrateNode, ARGS_ONE_NODE,
877 f8fa4175 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, DST_NODE_OPT,
878 1b7761fd Apollon Oikonomopoulos
     IALLOCATOR_OPT, PRIORITY_OPT],
879 6ea815cf Iustin Pop
    "[-f] <node>",
880 6ea815cf Iustin Pop
    "Migrate all the primary instance on a node away from it"
881 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
882 d0c8c01d Iustin Pop
  "info": (
883 064c21f8 Iustin Pop
    ShowNodeConfig, ARGS_MANY_NODES, [],
884 6ea815cf Iustin Pop
    "[<node_name>...]", "Show information about the node(s)"),
885 d0c8c01d Iustin Pop
  "list": (
886 6ea815cf Iustin Pop
    ListNodes, ARGS_MANY_NODES,
887 2afd577f Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT,
888 2afd577f Michael Hanselmann
     FORCE_FILTER_OPT],
889 6ea815cf Iustin Pop
    "[nodes...]",
890 7f5443a0 Michael Hanselmann
    "Lists the nodes in the cluster. The available fields can be shown using"
891 7f5443a0 Michael Hanselmann
    " the \"list-fields\" command (see the man page for details)."
892 7f5443a0 Michael Hanselmann
    " The default field list is (in order): %s." %
893 7f5443a0 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS)),
894 7f5443a0 Michael Hanselmann
  "list-fields": (
895 7f5443a0 Michael Hanselmann
    ListNodeFields, [ArgUnknown()],
896 7f5443a0 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
897 7f5443a0 Michael Hanselmann
    "[fields...]",
898 7f5443a0 Michael Hanselmann
    "Lists all available fields for nodes"),
899 d0c8c01d Iustin Pop
  "modify": (
900 6ea815cf Iustin Pop
    SetNodeParams, ARGS_ONE_NODE,
901 53919782 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, MC_OPT, DRAINED_OPT, OFFLINE_OPT,
902 4d32c211 Guido Trotter
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, SECONDARY_IP_OPT,
903 dd94e9f6 René Nussbaumer
     AUTO_PROMOTE_OPT, DRY_RUN_OPT, PRIORITY_OPT, NODE_PARAMS_OPT,
904 dd94e9f6 René Nussbaumer
     NODE_POWERED_OPT],
905 6ea815cf Iustin Pop
    "<node_name>", "Alters the parameters of a node"),
906 d0c8c01d Iustin Pop
  "powercycle": (
907 6ea815cf Iustin Pop
    PowercycleNode, ARGS_ONE_NODE,
908 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, CONFIRM_OPT, DRY_RUN_OPT, PRIORITY_OPT],
909 6ea815cf Iustin Pop
    "<node_name>", "Tries to forcefully powercycle a node"),
910 d0c8c01d Iustin Pop
  "power": (
911 abefdcff René Nussbaumer
    PowerNode,
912 abefdcff René Nussbaumer
    [ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS),
913 c832b6c8 René Nussbaumer
     ArgNode()],
914 efae0fdd René Nussbaumer
    [SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT, IGNORE_STATUS_OPT,
915 0a1fc31c René Nussbaumer
     FORCE_OPT, NOHDR_OPT, SEP_OPT, OOB_TIMEOUT_OPT, POWER_DELAY_OPT],
916 c832b6c8 René Nussbaumer
    "on|off|cycle|status [nodes...]",
917 abefdcff René Nussbaumer
    "Change power state of node by calling out-of-band helper."),
918 d0c8c01d Iustin Pop
  "remove": (
919 aa06f8c6 Michael Hanselmann
    RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT],
920 6ea815cf Iustin Pop
    "<node_name>", "Removes a node from the cluster"),
921 d0c8c01d Iustin Pop
  "volumes": (
922 6ea815cf Iustin Pop
    ListVolumes, [ArgNode()],
923 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, PRIORITY_OPT],
924 6ea815cf Iustin Pop
    "[<node_name>...]", "List logical volumes on node(s)"),
925 d0c8c01d Iustin Pop
  "list-storage": (
926 9b94905f Iustin Pop
    ListStorage, ARGS_MANY_NODES,
927 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, _STORAGE_TYPE_OPT,
928 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
929 620a85fd Iustin Pop
    "[<node_name>...]", "List physical volumes on node(s). The available"
930 620a85fd Iustin Pop
    " fields are (see the man page for details): %s." %
931 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_STOR_HEADERS))),
932 d0c8c01d Iustin Pop
  "modify-storage": (
933 9b94905f Iustin Pop
    ModifyStorage,
934 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
935 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_MODIFIABLE_STORAGE_TYPES),
936 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
937 aa06f8c6 Michael Hanselmann
    [ALLOCATABLE_OPT, DRY_RUN_OPT, PRIORITY_OPT],
938 064c21f8 Iustin Pop
    "<node_name> <storage_type> <name>", "Modify storage volume on a node"),
939 d0c8c01d Iustin Pop
  "repair-storage": (
940 9b94905f Iustin Pop
    RepairStorage,
941 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
942 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_REPAIRABLE_STORAGE_TYPES),
943 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
944 aa06f8c6 Michael Hanselmann
    [IGNORE_CONSIST_OPT, DRY_RUN_OPT, PRIORITY_OPT],
945 6ea815cf Iustin Pop
    "<node_name> <storage_type> <name>",
946 6ea815cf Iustin Pop
    "Repairs a storage volume on a node"),
947 d0c8c01d Iustin Pop
  "list-tags": (
948 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_NODE, [],
949 6ea815cf Iustin Pop
    "<node_name>", "List the tags of the given node"),
950 d0c8c01d Iustin Pop
  "add-tags": (
951 aa06f8c6 Michael Hanselmann
    AddTags, [ArgNode(min=1, max=1), ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
952 6ea815cf Iustin Pop
    "<node_name> tag...", "Add tags to the given node"),
953 d0c8c01d Iustin Pop
  "remove-tags": (
954 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()],
955 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
956 6ea815cf Iustin Pop
    "<node_name> tag...", "Remove tags from the given node"),
957 a0724772 René Nussbaumer
  "health": (
958 a0724772 René Nussbaumer
    Health, ARGS_MANY_NODES,
959 65a77fab René Nussbaumer
    [NOHDR_OPT, SEP_OPT, SUBMIT_OPT, PRIORITY_OPT, OOB_TIMEOUT_OPT],
960 a0724772 René Nussbaumer
    "[<node_name>...]", "List health of node(s) using out-of-band"),
961 a8083063 Iustin Pop
  }
962 a8083063 Iustin Pop
963 a8083063 Iustin Pop
964 37494fa4 Michael Hanselmann
def Main():
965 37494fa4 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_NODE})