Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 216d23c0

History | View | Annotate | Download (31.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 ef9fa5b9 René Nussbaumer
_ENV_OVERRIDE = frozenset(["list"])
110 ef9fa5b9 René Nussbaumer
111 ef9fa5b9 René Nussbaumer
112 2e6469a1 René Nussbaumer
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True,
113 2e6469a1 René Nussbaumer
                              action="store_false", dest="node_setup",
114 2e6469a1 René Nussbaumer
                              help=("Do not make initial SSH setup on remote"
115 2e6469a1 René Nussbaumer
                                    " node (needs to be done manually)"))
116 2e6469a1 René Nussbaumer
117 efae0fdd René Nussbaumer
IGNORE_STATUS_OPT = cli_option("--ignore-status", default=False,
118 efae0fdd René Nussbaumer
                               action="store_true", dest="ignore_status",
119 efae0fdd René Nussbaumer
                               help=("Ignore the Node(s) offline status"
120 efae0fdd René Nussbaumer
                                     " (potentially DANGEROUS)"))
121 efae0fdd René Nussbaumer
122 65a77fab René Nussbaumer
123 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
124 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
125 86f5eae3 Michael Hanselmann

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

137 2e6469a1 René Nussbaumer
  @param options: The command line options
138 2e6469a1 René Nussbaumer
  @param nodes: The nodes to setup
139 2e6469a1 René Nussbaumer

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

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

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

241 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
242 ebf366ee Iustin Pop
  @type args: list
243 982ed68e Adeodato Simo
  @param args: nodes to list, or empty for all
244 ebf366ee Iustin Pop
  @rtype: int
245 ebf366ee Iustin Pop
  @return: the desired exit code
246 ebf366ee Iustin Pop

247 a8083063 Iustin Pop
  """
248 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
249 a8083063 Iustin Pop
250 7f5443a0 Michael Hanselmann
  fmtoverride = dict.fromkeys(["pinst_list", "sinst_list", "tags"],
251 a36f605d Michael Hanselmann
                              (",".join, False))
252 a8083063 Iustin Pop
253 7f5443a0 Michael Hanselmann
  return GenericList(constants.QR_NODE, selected_fields, args, opts.units,
254 7f5443a0 Michael Hanselmann
                     opts.separator, not opts.no_headers,
255 2afd577f Michael Hanselmann
                     format_override=fmtoverride, verbose=opts.verbose,
256 2afd577f Michael Hanselmann
                     force_filter=opts.force_filter)
257 137161c9 Michael Hanselmann
258 137161c9 Michael Hanselmann
259 7f5443a0 Michael Hanselmann
def ListNodeFields(opts, args):
260 7f5443a0 Michael Hanselmann
  """List node fields.
261 ec223efb Iustin Pop

262 7f5443a0 Michael Hanselmann
  @param opts: the command line options selected by the user
263 7f5443a0 Michael Hanselmann
  @type args: list
264 7f5443a0 Michael Hanselmann
  @param args: fields to list, or empty for all
265 7f5443a0 Michael Hanselmann
  @rtype: int
266 7f5443a0 Michael Hanselmann
  @return: the desired exit code
267 a8083063 Iustin Pop

268 7f5443a0 Michael Hanselmann
  """
269 7f5443a0 Michael Hanselmann
  return GenericListFields(constants.QR_NODE, args, opts.separator,
270 7f5443a0 Michael Hanselmann
                           not opts.no_headers)
271 a8083063 Iustin Pop
272 a8083063 Iustin Pop
273 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
274 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
275 a5bc662a Iustin Pop

276 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
277 ebf366ee Iustin Pop
  @type args: list
278 ebf366ee Iustin Pop
  @param args: should be an empty list
279 ebf366ee Iustin Pop
  @rtype: int
280 ebf366ee Iustin Pop
  @return: the desired exit code
281 ebf366ee Iustin Pop

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

353 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
354 ebf366ee Iustin Pop
  @type args: list
355 ebf366ee Iustin Pop
  @param args: should be an empty list
356 ebf366ee Iustin Pop
  @rtype: int
357 ebf366ee Iustin Pop
  @return: the desired exit code
358 ebf366ee Iustin Pop

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

401 40ef0ed6 Iustin Pop
  """
402 40ef0ed6 Iustin Pop
  cl = GetClient()
403 40ef0ed6 Iustin Pop
  force = opts.force
404 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
405 40ef0ed6 Iustin Pop
406 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
407 b7a1c816 Michael Hanselmann
  ((node, pinst), ) = result
408 40ef0ed6 Iustin Pop
409 40ef0ed6 Iustin Pop
  if not pinst:
410 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
411 40ef0ed6 Iustin Pop
    return 0
412 40ef0ed6 Iustin Pop
413 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
414 40ef0ed6 Iustin Pop
415 b7a1c816 Michael Hanselmann
  if not (force or
416 b7a1c816 Michael Hanselmann
          AskUser("Migrate instance(s) %s?" %
417 b7a1c816 Michael Hanselmann
                  utils.CommaJoin(utils.NiceSort(pinst)))):
418 b7a1c816 Michael Hanselmann
    return constants.EXIT_CONFIRMATION
419 40ef0ed6 Iustin Pop
420 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
421 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
422 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
423 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
424 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
425 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
426 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
427 e71b9ef4 Iustin Pop
  else:
428 8c35561f Iustin Pop
    mode = opts.migration_mode
429 b7a1c816 Michael Hanselmann
430 1b7761fd Apollon Oikonomopoulos
  op = opcodes.OpNodeMigrate(node_name=args[0], mode=mode,
431 f8fa4175 Michael Hanselmann
                             iallocator=opts.iallocator,
432 9fa567b3 René Nussbaumer
                             target_node=opts.dst_node,
433 8c0b16f6 Guido Trotter
                             allow_runtime_changes=opts.allow_runtime_chgs,
434 9fa567b3 René Nussbaumer
                             ignore_ipolicy=opts.ignore_ipolicy)
435 b7a1c816 Michael Hanselmann
436 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts, cl=cl)
437 b7a1c816 Michael Hanselmann
438 b7a1c816 Michael Hanselmann
  # Keep track of submitted jobs
439 b7a1c816 Michael Hanselmann
  jex = JobExecutor(cl=cl, opts=opts)
440 b7a1c816 Michael Hanselmann
441 b7a1c816 Michael Hanselmann
  for (status, job_id) in result[constants.JOB_IDS_KEY]:
442 b7a1c816 Michael Hanselmann
    jex.AddJobId(None, status, job_id)
443 b7a1c816 Michael Hanselmann
444 b7a1c816 Michael Hanselmann
  results = jex.GetResults()
445 b7a1c816 Michael Hanselmann
  bad_cnt = len([row for row in results if not row[0]])
446 b7a1c816 Michael Hanselmann
  if bad_cnt == 0:
447 b7a1c816 Michael Hanselmann
    ToStdout("All instances migrated successfully.")
448 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_SUCCESS
449 b7a1c816 Michael Hanselmann
  else:
450 b7a1c816 Michael Hanselmann
    ToStdout("There were %s errors during the node migration.", bad_cnt)
451 b7a1c816 Michael Hanselmann
    rcode = constants.EXIT_FAILURE
452 b7a1c816 Michael Hanselmann
453 b7a1c816 Michael Hanselmann
  return rcode
454 40ef0ed6 Iustin Pop
455 40ef0ed6 Iustin Pop
456 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
457 a8083063 Iustin Pop
  """Show node information.
458 a8083063 Iustin Pop

459 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
460 ebf366ee Iustin Pop
  @type args: list
461 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
462 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
463 ebf366ee Iustin Pop
      a list of nodes to be queried for information
464 ebf366ee Iustin Pop
  @rtype: int
465 ebf366ee Iustin Pop
  @return: the desired exit code
466 ebf366ee Iustin Pop

467 a8083063 Iustin Pop
  """
468 2e7b8369 Iustin Pop
  cl = GetClient()
469 2e7b8369 Iustin Pop
  result = cl.QueryNodes(fields=["name", "pip", "sip",
470 0b2454b9 Iustin Pop
                                 "pinst_list", "sinst_list",
471 7b4978ad Iustin Pop
                                 "master_candidate", "drained", "offline",
472 8572f1fe René Nussbaumer
                                 "master_capable", "vm_capable", "powered",
473 8572f1fe René Nussbaumer
                                 "ndparams", "custom_ndparams"],
474 77921a95 Iustin Pop
                         names=args, use_locking=False)
475 a8083063 Iustin Pop
476 8572f1fe René Nussbaumer
  for (name, primary_ip, secondary_ip, pinst, sinst, is_mc, drained, offline,
477 8572f1fe René Nussbaumer
       master_capable, vm_capable, powered, ndparams,
478 8572f1fe René Nussbaumer
       ndparams_custom) in result:
479 3a24c527 Iustin Pop
    ToStdout("Node name: %s", name)
480 3a24c527 Iustin Pop
    ToStdout("  primary ip: %s", primary_ip)
481 3a24c527 Iustin Pop
    ToStdout("  secondary ip: %s", secondary_ip)
482 0b2454b9 Iustin Pop
    ToStdout("  master candidate: %s", is_mc)
483 0b2454b9 Iustin Pop
    ToStdout("  drained: %s", drained)
484 0b2454b9 Iustin Pop
    ToStdout("  offline: %s", offline)
485 016acd85 René Nussbaumer
    if powered is not None:
486 016acd85 René Nussbaumer
      ToStdout("  powered: %s", powered)
487 7b4978ad Iustin Pop
    ToStdout("  master_capable: %s", master_capable)
488 7b4978ad Iustin Pop
    ToStdout("  vm_capable: %s", vm_capable)
489 7b4978ad Iustin Pop
    if vm_capable:
490 7b4978ad Iustin Pop
      if pinst:
491 7b4978ad Iustin Pop
        ToStdout("  primary for instances:")
492 7b4978ad Iustin Pop
        for iname in utils.NiceSort(pinst):
493 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
494 7b4978ad Iustin Pop
      else:
495 7b4978ad Iustin Pop
        ToStdout("  primary for no instances")
496 7b4978ad Iustin Pop
      if sinst:
497 7b4978ad Iustin Pop
        ToStdout("  secondary for instances:")
498 7b4978ad Iustin Pop
        for iname in utils.NiceSort(sinst):
499 7b4978ad Iustin Pop
          ToStdout("    - %s", iname)
500 7b4978ad Iustin Pop
      else:
501 7b4978ad Iustin Pop
        ToStdout("  secondary for no instances")
502 8572f1fe René Nussbaumer
    ToStdout("  node parameters:")
503 8572f1fe René Nussbaumer
    buf = StringIO()
504 8572f1fe René Nussbaumer
    FormatParameterDict(buf, ndparams_custom, ndparams, level=2)
505 8572f1fe René Nussbaumer
    ToStdout(buf.getvalue().rstrip("\n"))
506 a8083063 Iustin Pop
507 a8083063 Iustin Pop
  return 0
508 a8083063 Iustin Pop
509 a8083063 Iustin Pop
510 a8083063 Iustin Pop
def RemoveNode(opts, args):
511 ebf366ee Iustin Pop
  """Remove a node from the cluster.
512 ebf366ee Iustin Pop

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

520 ebf366ee Iustin Pop
  """
521 73d565a3 Iustin Pop
  op = opcodes.OpNodeRemove(node_name=args[0])
522 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
523 ebf366ee Iustin Pop
  return 0
524 a8083063 Iustin Pop
525 a8083063 Iustin Pop
526 f5118ade Iustin Pop
def PowercycleNode(opts, args):
527 f5118ade Iustin Pop
  """Remove a node from the cluster.
528 f5118ade Iustin Pop

529 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
530 f5118ade Iustin Pop
  @type args: list
531 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
532 f5118ade Iustin Pop
      the node to be removed
533 f5118ade Iustin Pop
  @rtype: int
534 f5118ade Iustin Pop
  @return: the desired exit code
535 f5118ade Iustin Pop

536 f5118ade Iustin Pop
  """
537 f5118ade Iustin Pop
  node = args[0]
538 f5118ade Iustin Pop
  if (not opts.confirm and
539 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
540 f5118ade Iustin Pop
    return 2
541 f5118ade Iustin Pop
542 e0d4735f Iustin Pop
  op = opcodes.OpNodePowercycle(node_name=node, force=opts.force)
543 c5a66db3 Michael Hanselmann
  result = SubmitOrSend(op, opts)
544 48418fea Iustin Pop
  if result:
545 48418fea Iustin Pop
    ToStderr(result)
546 f5118ade Iustin Pop
  return 0
547 f5118ade Iustin Pop
548 f5118ade Iustin Pop
549 abefdcff René Nussbaumer
def PowerNode(opts, args):
550 abefdcff René Nussbaumer
  """Change/ask power state of a node.
551 abefdcff René Nussbaumer

552 abefdcff René Nussbaumer
  @param opts: the command line options selected by the user
553 abefdcff René Nussbaumer
  @type args: list
554 abefdcff René Nussbaumer
  @param args: should contain only one element, the name of
555 abefdcff René Nussbaumer
      the node to be removed
556 abefdcff René Nussbaumer
  @rtype: int
557 abefdcff René Nussbaumer
  @return: the desired exit code
558 abefdcff René Nussbaumer

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

638 a0724772 René Nussbaumer
  @param opts: the command line options selected by the user
639 a0724772 René Nussbaumer
  @type args: list
640 a0724772 René Nussbaumer
  @param args: should contain only one element, the name of
641 a0724772 René Nussbaumer
      the node to be removed
642 a0724772 René Nussbaumer
  @rtype: int
643 a0724772 René Nussbaumer
  @return: the desired exit code
644 a0724772 René Nussbaumer

645 a0724772 René Nussbaumer
  """
646 65a77fab René Nussbaumer
  op = opcodes.OpOobCommand(node_names=args, command=constants.OOB_HEALTH,
647 65a77fab René Nussbaumer
                            timeout=opts.oob_timeout)
648 a0724772 René Nussbaumer
  result = SubmitOpCode(op, opts=opts)
649 a0724772 René Nussbaumer
650 a0724772 René Nussbaumer
  if opts.no_headers:
651 a0724772 René Nussbaumer
    headers = None
652 a0724772 René Nussbaumer
  else:
653 a0724772 René Nussbaumer
    headers = {"node": "Node", "status": "Status"}
654 a0724772 René Nussbaumer
655 a0724772 René Nussbaumer
  errs = 0
656 a0724772 René Nussbaumer
  data = []
657 a0724772 René Nussbaumer
  for node_result in result:
658 a0724772 René Nussbaumer
    (node_tuple, data_tuple) = node_result
659 a0724772 René Nussbaumer
    (_, node_name) = node_tuple
660 a0724772 René Nussbaumer
    (data_status, data_node) = data_tuple
661 a0724772 René Nussbaumer
    if data_status == constants.RS_NORMAL:
662 a0724772 René Nussbaumer
      data.append([node_name, "%s=%s" % tuple(data_node[0])])
663 a0724772 René Nussbaumer
      for item, status in data_node[1:]:
664 a0724772 René Nussbaumer
        data.append(["", "%s=%s" % (item, status)])
665 a0724772 René Nussbaumer
    else:
666 a0724772 René Nussbaumer
      errs += 1
667 f2c6673d Michael Hanselmann
      data.append([node_name, cli.FormatResultError(data_status, True)])
668 a0724772 René Nussbaumer
669 a0724772 René Nussbaumer
  data = GenerateTable(separator=opts.separator, headers=headers,
670 a0724772 René Nussbaumer
                       fields=["node", "status"], data=data)
671 a0724772 René Nussbaumer
672 a0724772 René Nussbaumer
  for line in data:
673 a0724772 René Nussbaumer
    ToStdout(line)
674 a0724772 René Nussbaumer
675 a0724772 René Nussbaumer
  if errs:
676 a0724772 René Nussbaumer
    return constants.EXIT_FAILURE
677 a0724772 René Nussbaumer
  else:
678 a0724772 René Nussbaumer
    return constants.EXIT_SUCCESS
679 a0724772 René Nussbaumer
680 a0724772 René Nussbaumer
681 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
682 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
683 dcb93971 Michael Hanselmann

684 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
685 ebf366ee Iustin Pop
  @type args: list
686 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
687 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
688 ebf366ee Iustin Pop
      to display data only for those
689 ebf366ee Iustin Pop
  @rtype: int
690 ebf366ee Iustin Pop
  @return: the desired exit code
691 ebf366ee Iustin Pop

692 dcb93971 Michael Hanselmann
  """
693 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
694 dcb93971 Michael Hanselmann
695 8ed55bfd Iustin Pop
  op = opcodes.OpNodeQueryvols(nodes=args, output_fields=selected_fields)
696 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
697 dcb93971 Michael Hanselmann
698 dcb93971 Michael Hanselmann
  if not opts.no_headers:
699 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
700 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
701 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
702 137161c9 Michael Hanselmann
  else:
703 137161c9 Michael Hanselmann
    headers = None
704 137161c9 Michael Hanselmann
705 9fbfbb7b Iustin Pop
  unitfields = ["size"]
706 137161c9 Michael Hanselmann
707 137161c9 Michael Hanselmann
  numfields = ["size"]
708 137161c9 Michael Hanselmann
709 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
710 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
711 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
712 16be8703 Iustin Pop
713 16be8703 Iustin Pop
  for line in data:
714 3a24c527 Iustin Pop
    ToStdout(line)
715 dcb93971 Michael Hanselmann
716 dcb93971 Michael Hanselmann
  return 0
717 dcb93971 Michael Hanselmann
718 dcb93971 Michael Hanselmann
719 9b94905f Iustin Pop
def ListStorage(opts, args):
720 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
721 4007f57d Michael Hanselmann

722 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
723 4007f57d Michael Hanselmann
  @type args: list
724 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
725 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
726 4007f57d Michael Hanselmann
      to display data only for those
727 4007f57d Michael Hanselmann
  @rtype: int
728 4007f57d Michael Hanselmann
  @return: the desired exit code
729 4007f57d Michael Hanselmann

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

784 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
785 0e89fc2d Michael Hanselmann
  @type args: list
786 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
787 0e89fc2d Michael Hanselmann
  @rtype: int
788 0e89fc2d Michael Hanselmann
  @return: the desired exit code
789 0e89fc2d Michael Hanselmann

790 0e89fc2d Michael Hanselmann
  """
791 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
792 0e89fc2d Michael Hanselmann
793 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
794 0e89fc2d Michael Hanselmann
795 0e89fc2d Michael Hanselmann
  changes = {}
796 0e89fc2d Michael Hanselmann
797 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
798 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
799 0e89fc2d Michael Hanselmann
800 0e89fc2d Michael Hanselmann
  if changes:
801 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
802 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
803 0e89fc2d Michael Hanselmann
                                     name=volume_name,
804 0e89fc2d Michael Hanselmann
                                     changes=changes)
805 c5a66db3 Michael Hanselmann
    SubmitOrSend(op, opts)
806 620a85fd Iustin Pop
  else:
807 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
808 0e89fc2d Michael Hanselmann
809 0e89fc2d Michael Hanselmann
810 9b94905f Iustin Pop
def RepairStorage(opts, args):
811 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
812 1e3463f1 Michael Hanselmann

813 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
814 1e3463f1 Michael Hanselmann
  @type args: list
815 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
816 1e3463f1 Michael Hanselmann
  @rtype: int
817 1e3463f1 Michael Hanselmann
  @return: the desired exit code
818 1e3463f1 Michael Hanselmann

819 1e3463f1 Michael Hanselmann
  """
820 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
821 1e3463f1 Michael Hanselmann
822 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
823 1e3463f1 Michael Hanselmann
824 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
825 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
826 7e9c6a78 Iustin Pop
                                   name=volume_name,
827 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
828 c5a66db3 Michael Hanselmann
  SubmitOrSend(op, opts)
829 1e3463f1 Michael Hanselmann
830 1e3463f1 Michael Hanselmann
831 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
832 b31c8676 Iustin Pop
  """Modifies a node.
833 b31c8676 Iustin Pop

834 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
835 b31c8676 Iustin Pop
  @type args: list
836 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
837 b31c8676 Iustin Pop
  @rtype: int
838 b31c8676 Iustin Pop
  @return: the desired exit code
839 b31c8676 Iustin Pop

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