Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 36c70d4d

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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