Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ f0b1bafe

History | View | Annotate | Download (25.6 kB)

1 37494fa4 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 668f755d Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 7260cfbe Iustin Pop
"""Node related commands"""
22 a8083063 Iustin Pop
23 2d54e29c Iustin Pop
# pylint: disable-msg=W0401,W0613,W0614,C0103
24 2f79bd34 Iustin Pop
# W0401: Wildcard import ganeti.cli
25 2d54e29c Iustin Pop
# W0613: Unused argument, since all functions follow the same API
26 2f79bd34 Iustin Pop
# W0614: Unused import %s from wildcard import (since we need cli)
27 7260cfbe Iustin Pop
# C0103: Invalid name gnt-node
28 2f79bd34 Iustin Pop
29 a8083063 Iustin Pop
from ganeti.cli import *
30 d363797e René Nussbaumer
from ganeti import cli
31 3ef51126 René Nussbaumer
from ganeti import bootstrap
32 a8083063 Iustin Pop
from ganeti import opcodes
33 a8083063 Iustin Pop
from ganeti import utils
34 846baef9 Iustin Pop
from ganeti import constants
35 c450e9b0 Iustin Pop
from ganeti import errors
36 a744b676 Manuel Franceschini
from ganeti import netutils
37 8572f1fe René Nussbaumer
from cStringIO import StringIO
38 a8083063 Iustin Pop
39 a8083063 Iustin Pop
40 ebf366ee Iustin Pop
#: default list of field for L{ListNodes}
41 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
42 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
43 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
44 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
45 48c4dfa8 Iustin Pop
  ]
46 48c4dfa8 Iustin Pop
47 620a85fd Iustin Pop
48 a4ebd726 Michael Hanselmann
#: Default field list for L{ListVolumes}
49 a4ebd726 Michael Hanselmann
_LIST_VOL_DEF_FIELDS = ["node", "phys", "vg", "name", "size", "instance"]
50 a4ebd726 Michael Hanselmann
51 a4ebd726 Michael Hanselmann
52 620a85fd Iustin Pop
#: default list of field for L{ListStorage}
53 620a85fd Iustin Pop
_LIST_STOR_DEF_FIELDS = [
54 620a85fd Iustin Pop
  constants.SF_NODE,
55 620a85fd Iustin Pop
  constants.SF_TYPE,
56 620a85fd Iustin Pop
  constants.SF_NAME,
57 620a85fd Iustin Pop
  constants.SF_SIZE,
58 620a85fd Iustin Pop
  constants.SF_USED,
59 620a85fd Iustin Pop
  constants.SF_FREE,
60 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE,
61 620a85fd Iustin Pop
  ]
62 620a85fd Iustin Pop
63 620a85fd Iustin Pop
64 abefdcff René Nussbaumer
#: default list of power commands
65 abefdcff René Nussbaumer
_LIST_POWER_COMMANDS = ["on", "off", "cycle", "status"]
66 abefdcff René Nussbaumer
67 abefdcff René Nussbaumer
68 982ed68e Adeodato Simo
#: headers (and full field list) for L{ListStorage}
69 620a85fd Iustin Pop
_LIST_STOR_HEADERS = {
70 620a85fd Iustin Pop
  constants.SF_NODE: "Node",
71 620a85fd Iustin Pop
  constants.SF_TYPE: "Type",
72 620a85fd Iustin Pop
  constants.SF_NAME: "Name",
73 620a85fd Iustin Pop
  constants.SF_SIZE: "Size",
74 620a85fd Iustin Pop
  constants.SF_USED: "Used",
75 620a85fd Iustin Pop
  constants.SF_FREE: "Free",
76 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE: "Allocatable",
77 620a85fd Iustin Pop
  }
78 620a85fd Iustin Pop
79 620a85fd Iustin Pop
80 0e89fc2d Michael Hanselmann
#: User-facing storage unit types
81 0e89fc2d Michael Hanselmann
_USER_STORAGE_TYPE = {
82 0e89fc2d Michael Hanselmann
  constants.ST_FILE: "file",
83 0e89fc2d Michael Hanselmann
  constants.ST_LVM_PV: "lvm-pv",
84 0e89fc2d Michael Hanselmann
  constants.ST_LVM_VG: "lvm-vg",
85 0e89fc2d Michael Hanselmann
  }
86 0e89fc2d Michael Hanselmann
87 a8005e17 Michael Hanselmann
_STORAGE_TYPE_OPT = \
88 aeaefce8 Iustin Pop
  cli_option("-t", "--storage-type",
89 a8005e17 Michael Hanselmann
             dest="user_storage_type",
90 a8005e17 Michael Hanselmann
             choices=_USER_STORAGE_TYPE.keys(),
91 a8005e17 Michael Hanselmann
             default=None,
92 a8005e17 Michael Hanselmann
             metavar="STORAGE_TYPE",
93 ab3e6da8 Iustin Pop
             help=("Storage type (%s)" %
94 ab3e6da8 Iustin Pop
                   utils.CommaJoin(_USER_STORAGE_TYPE.keys())))
95 a8005e17 Michael Hanselmann
96 a8005e17 Michael Hanselmann
_REPAIRABLE_STORAGE_TYPES = \
97 a8005e17 Michael Hanselmann
  [st for st, so in constants.VALID_STORAGE_OPERATIONS.iteritems()
98 a8005e17 Michael Hanselmann
   if constants.SO_FIX_CONSISTENCY in so]
99 a8005e17 Michael Hanselmann
100 a8005e17 Michael Hanselmann
_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys()
101 a8005e17 Michael Hanselmann
102 51144e33 Michael Hanselmann
103 2e6469a1 René Nussbaumer
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True,
104 2e6469a1 René Nussbaumer
                              action="store_false", dest="node_setup",
105 2e6469a1 René Nussbaumer
                              help=("Do not make initial SSH setup on remote"
106 2e6469a1 René Nussbaumer
                                    " node (needs to be done manually)"))
107 2e6469a1 René Nussbaumer
108 2e6469a1 René Nussbaumer
109 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
110 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
111 86f5eae3 Michael Hanselmann

112 86f5eae3 Michael Hanselmann
  """
113 86f5eae3 Michael Hanselmann
  try:
114 86f5eae3 Michael Hanselmann
    return _USER_STORAGE_TYPE[user_storage_type]
115 86f5eae3 Michael Hanselmann
  except KeyError:
116 debac808 Iustin Pop
    raise errors.OpPrereqError("Unknown storage type: %s" % user_storage_type,
117 debac808 Iustin Pop
                               errors.ECODE_INVAL)
118 86f5eae3 Michael Hanselmann
119 86f5eae3 Michael Hanselmann
120 2e6469a1 René Nussbaumer
def _RunSetupSSH(options, nodes):
121 2e6469a1 René Nussbaumer
  """Wrapper around utils.RunCmd to call setup-ssh
122 2e6469a1 René Nussbaumer

123 2e6469a1 René Nussbaumer
  @param options: The command line options
124 2e6469a1 René Nussbaumer
  @param nodes: The nodes to setup
125 2e6469a1 René Nussbaumer

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

154 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
155 ebf366ee Iustin Pop
  @type args: list
156 ebf366ee Iustin Pop
  @param args: should contain only one element, the new node name
157 ebf366ee Iustin Pop
  @rtype: int
158 ebf366ee Iustin Pop
  @return: the desired exit code
159 05ccd983 Guido Trotter

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

212 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
213 ebf366ee Iustin Pop
  @type args: list
214 982ed68e Adeodato Simo
  @param args: nodes to list, or empty for all
215 ebf366ee Iustin Pop
  @rtype: int
216 ebf366ee Iustin Pop
  @return: the desired exit code
217 ebf366ee Iustin Pop

218 a8083063 Iustin Pop
  """
219 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_DEF_FIELDS)
220 a8083063 Iustin Pop
221 7f5443a0 Michael Hanselmann
  fmtoverride = dict.fromkeys(["pinst_list", "sinst_list", "tags"],
222 a36f605d Michael Hanselmann
                              (",".join, False))
223 a8083063 Iustin Pop
224 7f5443a0 Michael Hanselmann
  return GenericList(constants.QR_NODE, selected_fields, args, opts.units,
225 7f5443a0 Michael Hanselmann
                     opts.separator, not opts.no_headers,
226 f0b1bafe Iustin Pop
                     format_override=fmtoverride, verbose=opts.verbose)
227 137161c9 Michael Hanselmann
228 137161c9 Michael Hanselmann
229 7f5443a0 Michael Hanselmann
def ListNodeFields(opts, args):
230 7f5443a0 Michael Hanselmann
  """List node fields.
231 ec223efb Iustin Pop

232 7f5443a0 Michael Hanselmann
  @param opts: the command line options selected by the user
233 7f5443a0 Michael Hanselmann
  @type args: list
234 7f5443a0 Michael Hanselmann
  @param args: fields to list, or empty for all
235 7f5443a0 Michael Hanselmann
  @rtype: int
236 7f5443a0 Michael Hanselmann
  @return: the desired exit code
237 a8083063 Iustin Pop

238 7f5443a0 Michael Hanselmann
  """
239 7f5443a0 Michael Hanselmann
  return GenericListFields(constants.QR_NODE, args, opts.separator,
240 7f5443a0 Michael Hanselmann
                           not opts.no_headers)
241 a8083063 Iustin Pop
242 a8083063 Iustin Pop
243 a5bc662a Iustin Pop
def EvacuateNode(opts, args):
244 a5bc662a Iustin Pop
  """Relocate all secondary instance from a node.
245 a5bc662a Iustin Pop

246 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
247 ebf366ee Iustin Pop
  @type args: list
248 ebf366ee Iustin Pop
  @param args: should be an empty list
249 ebf366ee Iustin Pop
  @rtype: int
250 ebf366ee Iustin Pop
  @return: the desired exit code
251 ebf366ee Iustin Pop

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

300 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
301 ebf366ee Iustin Pop
  @type args: list
302 ebf366ee Iustin Pop
  @param args: should be an empty list
303 ebf366ee Iustin Pop
  @rtype: int
304 ebf366ee Iustin Pop
  @return: the desired exit code
305 ebf366ee Iustin Pop

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

347 40ef0ed6 Iustin Pop
  """
348 40ef0ed6 Iustin Pop
  cl = GetClient()
349 40ef0ed6 Iustin Pop
  force = opts.force
350 40ef0ed6 Iustin Pop
  selected_fields = ["name", "pinst_list"]
351 40ef0ed6 Iustin Pop
352 77921a95 Iustin Pop
  result = cl.QueryNodes(names=args, fields=selected_fields, use_locking=False)
353 40ef0ed6 Iustin Pop
  node, pinst = result[0]
354 40ef0ed6 Iustin Pop
355 40ef0ed6 Iustin Pop
  if not pinst:
356 40ef0ed6 Iustin Pop
    ToStdout("No primary instances on node %s, exiting." % node)
357 40ef0ed6 Iustin Pop
    return 0
358 40ef0ed6 Iustin Pop
359 40ef0ed6 Iustin Pop
  pinst = utils.NiceSort(pinst)
360 40ef0ed6 Iustin Pop
361 40ef0ed6 Iustin Pop
  if not force and not AskUser("Migrate instance(s) %s?" %
362 40ef0ed6 Iustin Pop
                               (",".join("'%s'" % name for name in pinst))):
363 40ef0ed6 Iustin Pop
    return 2
364 40ef0ed6 Iustin Pop
365 e71b9ef4 Iustin Pop
  # this should be removed once --non-live is deprecated
366 783a6c0b Iustin Pop
  if not opts.live and opts.migration_mode is not None:
367 e71b9ef4 Iustin Pop
    raise errors.OpPrereqError("Only one of the --non-live and "
368 783a6c0b Iustin Pop
                               "--migration-mode options can be passed",
369 e71b9ef4 Iustin Pop
                               errors.ECODE_INVAL)
370 e71b9ef4 Iustin Pop
  if not opts.live: # --non-live passed
371 8c35561f Iustin Pop
    mode = constants.HT_MIGRATION_NONLIVE
372 e71b9ef4 Iustin Pop
  else:
373 8c35561f Iustin Pop
    mode = opts.migration_mode
374 5b14a488 Iustin Pop
  op = opcodes.OpNodeMigrate(node_name=args[0], mode=mode)
375 400ca2f7 Iustin Pop
  SubmitOpCode(op, cl=cl, opts=opts)
376 40ef0ed6 Iustin Pop
377 40ef0ed6 Iustin Pop
378 a8083063 Iustin Pop
def ShowNodeConfig(opts, args):
379 a8083063 Iustin Pop
  """Show node information.
380 a8083063 Iustin Pop

381 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
382 ebf366ee Iustin Pop
  @type args: list
383 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
384 ebf366ee Iustin Pop
      we show information about all nodes, or should contain
385 ebf366ee Iustin Pop
      a list of nodes to be queried for information
386 ebf366ee Iustin Pop
  @rtype: int
387 ebf366ee Iustin Pop
  @return: the desired exit code
388 ebf366ee Iustin Pop

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

435 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
436 ebf366ee Iustin Pop
  @type args: list
437 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
438 ebf366ee Iustin Pop
      the node to be removed
439 ebf366ee Iustin Pop
  @rtype: int
440 ebf366ee Iustin Pop
  @return: the desired exit code
441 ebf366ee Iustin Pop

442 ebf366ee Iustin Pop
  """
443 73d565a3 Iustin Pop
  op = opcodes.OpNodeRemove(node_name=args[0])
444 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
445 ebf366ee Iustin Pop
  return 0
446 a8083063 Iustin Pop
447 a8083063 Iustin Pop
448 f5118ade Iustin Pop
def PowercycleNode(opts, args):
449 f5118ade Iustin Pop
  """Remove a node from the cluster.
450 f5118ade Iustin Pop

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

458 f5118ade Iustin Pop
  """
459 f5118ade Iustin Pop
  node = args[0]
460 f5118ade Iustin Pop
  if (not opts.confirm and
461 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
462 f5118ade Iustin Pop
    return 2
463 f5118ade Iustin Pop
464 e0d4735f Iustin Pop
  op = opcodes.OpNodePowercycle(node_name=node, force=opts.force)
465 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
466 48418fea Iustin Pop
  if result:
467 48418fea Iustin Pop
    ToStderr(result)
468 f5118ade Iustin Pop
  return 0
469 f5118ade Iustin Pop
470 f5118ade Iustin Pop
471 abefdcff René Nussbaumer
def PowerNode(opts, args):
472 abefdcff René Nussbaumer
  """Change/ask power state of a node.
473 abefdcff René Nussbaumer

474 abefdcff René Nussbaumer
  @param opts: the command line options selected by the user
475 abefdcff René Nussbaumer
  @type args: list
476 abefdcff René Nussbaumer
  @param args: should contain only one element, the name of
477 abefdcff René Nussbaumer
      the node to be removed
478 abefdcff René Nussbaumer
  @rtype: int
479 abefdcff René Nussbaumer
  @return: the desired exit code
480 abefdcff René Nussbaumer

481 abefdcff René Nussbaumer
  """
482 abefdcff René Nussbaumer
  command = args[0]
483 abefdcff René Nussbaumer
  node = args[1]
484 abefdcff René Nussbaumer
485 abefdcff René Nussbaumer
  if command not in _LIST_POWER_COMMANDS:
486 abefdcff René Nussbaumer
    ToStderr("power subcommand %s not supported." % command)
487 abefdcff René Nussbaumer
    return constants.EXIT_FAILURE
488 abefdcff René Nussbaumer
489 abefdcff René Nussbaumer
  oob_command = "power-%s" % command
490 abefdcff René Nussbaumer
491 d363797e René Nussbaumer
  opcodelist = []
492 d363797e René Nussbaumer
  if oob_command == constants.OOB_POWER_OFF:
493 f13973c4 Iustin Pop
    opcodelist.append(opcodes.OpNodeSetParams(node_name=node, offline=True,
494 d363797e René Nussbaumer
                                              auto_promote=opts.auto_promote))
495 d363797e René Nussbaumer
496 b04808ea René Nussbaumer
  opcodelist.append(opcodes.OpOobCommand(node_names=[node],
497 b04808ea René Nussbaumer
                                         command=oob_command))
498 d363797e René Nussbaumer
499 d363797e René Nussbaumer
  cli.SetGenericOpcodeOpts(opcodelist, opts)
500 d363797e René Nussbaumer
501 d363797e René Nussbaumer
  job_id = cli.SendJob(opcodelist)
502 d363797e René Nussbaumer
503 d363797e René Nussbaumer
  # We just want the OOB Opcode status
504 d363797e René Nussbaumer
  # If it fails PollJob gives us the error message in it
505 d363797e René Nussbaumer
  result = cli.PollJob(job_id)[-1]
506 d363797e René Nussbaumer
507 abefdcff René Nussbaumer
  if result:
508 b04808ea René Nussbaumer
    (_, data_tuple) = result[0]
509 b04808ea René Nussbaumer
    if data_tuple[0] != constants.RS_NORMAL:
510 b04808ea René Nussbaumer
      if data_tuple[0] == constants.RS_UNAVAIL:
511 b04808ea René Nussbaumer
        result = "OOB is not supported"
512 abefdcff René Nussbaumer
      else:
513 b04808ea René Nussbaumer
        result = "RPC failed, look out for warning in the output"
514 b04808ea René Nussbaumer
      ToStderr(result)
515 b04808ea René Nussbaumer
      return constants.EXIT_FAILURE
516 b04808ea René Nussbaumer
    else:
517 b04808ea René Nussbaumer
      if oob_command == constants.OOB_POWER_STATUS:
518 b04808ea René Nussbaumer
        text = "The machine is %spowered"
519 b04808ea René Nussbaumer
        if data_tuple[1][constants.OOB_POWER_STATUS_POWERED]:
520 b04808ea René Nussbaumer
          result = text % ""
521 b04808ea René Nussbaumer
        else:
522 b04808ea René Nussbaumer
          result = text % "not "
523 b04808ea René Nussbaumer
        ToStdout(result)
524 abefdcff René Nussbaumer
525 abefdcff René Nussbaumer
  return constants.EXIT_SUCCESS
526 abefdcff René Nussbaumer
527 abefdcff René Nussbaumer
528 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
529 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
530 dcb93971 Michael Hanselmann

531 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
532 ebf366ee Iustin Pop
  @type args: list
533 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
534 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
535 ebf366ee Iustin Pop
      to display data only for those
536 ebf366ee Iustin Pop
  @rtype: int
537 ebf366ee Iustin Pop
  @return: the desired exit code
538 ebf366ee Iustin Pop

539 dcb93971 Michael Hanselmann
  """
540 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
541 dcb93971 Michael Hanselmann
542 8ed55bfd Iustin Pop
  op = opcodes.OpNodeQueryvols(nodes=args, output_fields=selected_fields)
543 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
544 dcb93971 Michael Hanselmann
545 dcb93971 Michael Hanselmann
  if not opts.no_headers:
546 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
547 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
548 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
549 137161c9 Michael Hanselmann
  else:
550 137161c9 Michael Hanselmann
    headers = None
551 137161c9 Michael Hanselmann
552 9fbfbb7b Iustin Pop
  unitfields = ["size"]
553 137161c9 Michael Hanselmann
554 137161c9 Michael Hanselmann
  numfields = ["size"]
555 137161c9 Michael Hanselmann
556 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
557 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
558 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
559 16be8703 Iustin Pop
560 16be8703 Iustin Pop
  for line in data:
561 3a24c527 Iustin Pop
    ToStdout(line)
562 dcb93971 Michael Hanselmann
563 dcb93971 Michael Hanselmann
  return 0
564 dcb93971 Michael Hanselmann
565 dcb93971 Michael Hanselmann
566 9b94905f Iustin Pop
def ListStorage(opts, args):
567 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
568 4007f57d Michael Hanselmann

569 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
570 4007f57d Michael Hanselmann
  @type args: list
571 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
572 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
573 4007f57d Michael Hanselmann
      to display data only for those
574 4007f57d Michael Hanselmann
  @rtype: int
575 4007f57d Michael Hanselmann
  @return: the desired exit code
576 4007f57d Michael Hanselmann

577 4007f57d Michael Hanselmann
  """
578 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
579 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
580 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
581 53548798 Michael Hanselmann
582 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
583 53548798 Michael Hanselmann
584 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
585 4007f57d Michael Hanselmann
586 ad8d0595 Iustin Pop
  op = opcodes.OpNodeQueryStorage(nodes=args,
587 53548798 Michael Hanselmann
                                  storage_type=storage_type,
588 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
589 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
590 4007f57d Michael Hanselmann
591 4007f57d Michael Hanselmann
  if not opts.no_headers:
592 4007f57d Michael Hanselmann
    headers = {
593 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
594 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
595 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
596 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
597 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
598 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
599 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
600 4007f57d Michael Hanselmann
      }
601 4007f57d Michael Hanselmann
  else:
602 4007f57d Michael Hanselmann
    headers = None
603 4007f57d Michael Hanselmann
604 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
605 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
606 4007f57d Michael Hanselmann
607 dc09c3cf Iustin Pop
  # change raw values to nicer strings
608 dc09c3cf Iustin Pop
  for row in output:
609 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
610 dc09c3cf Iustin Pop
      val = row[idx]
611 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
612 dc09c3cf Iustin Pop
        if val:
613 dc09c3cf Iustin Pop
          val = "Y"
614 dc09c3cf Iustin Pop
        else:
615 dc09c3cf Iustin Pop
          val = "N"
616 dc09c3cf Iustin Pop
      row[idx] = str(val)
617 dc09c3cf Iustin Pop
618 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
619 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
620 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
621 4007f57d Michael Hanselmann
622 4007f57d Michael Hanselmann
  for line in data:
623 4007f57d Michael Hanselmann
    ToStdout(line)
624 4007f57d Michael Hanselmann
625 4007f57d Michael Hanselmann
  return 0
626 4007f57d Michael Hanselmann
627 4007f57d Michael Hanselmann
628 9b94905f Iustin Pop
def ModifyStorage(opts, args):
629 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
630 0e89fc2d Michael Hanselmann

631 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
632 0e89fc2d Michael Hanselmann
  @type args: list
633 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
634 0e89fc2d Michael Hanselmann
  @rtype: int
635 0e89fc2d Michael Hanselmann
  @return: the desired exit code
636 0e89fc2d Michael Hanselmann

637 0e89fc2d Michael Hanselmann
  """
638 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
639 0e89fc2d Michael Hanselmann
640 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
641 0e89fc2d Michael Hanselmann
642 0e89fc2d Michael Hanselmann
  changes = {}
643 0e89fc2d Michael Hanselmann
644 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
645 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
646 0e89fc2d Michael Hanselmann
647 0e89fc2d Michael Hanselmann
  if changes:
648 2cee4077 Iustin Pop
    op = opcodes.OpNodeModifyStorage(node_name=node_name,
649 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
650 0e89fc2d Michael Hanselmann
                                     name=volume_name,
651 0e89fc2d Michael Hanselmann
                                     changes=changes)
652 400ca2f7 Iustin Pop
    SubmitOpCode(op, opts=opts)
653 620a85fd Iustin Pop
  else:
654 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
655 0e89fc2d Michael Hanselmann
656 0e89fc2d Michael Hanselmann
657 9b94905f Iustin Pop
def RepairStorage(opts, args):
658 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
659 1e3463f1 Michael Hanselmann

660 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
661 1e3463f1 Michael Hanselmann
  @type args: list
662 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
663 1e3463f1 Michael Hanselmann
  @rtype: int
664 1e3463f1 Michael Hanselmann
  @return: the desired exit code
665 1e3463f1 Michael Hanselmann

666 1e3463f1 Michael Hanselmann
  """
667 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
668 1e3463f1 Michael Hanselmann
669 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
670 1e3463f1 Michael Hanselmann
671 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
672 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
673 7e9c6a78 Iustin Pop
                                   name=volume_name,
674 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
675 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
676 1e3463f1 Michael Hanselmann
677 1e3463f1 Michael Hanselmann
678 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
679 b31c8676 Iustin Pop
  """Modifies a node.
680 b31c8676 Iustin Pop

681 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
682 b31c8676 Iustin Pop
  @type args: list
683 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
684 b31c8676 Iustin Pop
  @rtype: int
685 b31c8676 Iustin Pop
  @return: the desired exit code
686 b31c8676 Iustin Pop

687 b31c8676 Iustin Pop
  """
688 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
689 4e37f591 René Nussbaumer
                 opts.master_capable, opts.vm_capable, opts.secondary_ip,
690 4e37f591 René Nussbaumer
                 opts.ndparams]
691 53919782 Iustin Pop
  if all_changes.count(None) == len(all_changes):
692 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
693 b31c8676 Iustin Pop
    return 1
694 b31c8676 Iustin Pop
695 f13973c4 Iustin Pop
  op = opcodes.OpNodeSetParams(node_name=args[0],
696 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
697 e7b61bb0 Iustin Pop
                               offline=opts.offline,
698 e7b61bb0 Iustin Pop
                               drained=opts.drained,
699 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
700 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
701 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
702 4c61d894 Iustin Pop
                               force=opts.force,
703 4e37f591 René Nussbaumer
                               ndparams=opts.ndparams,
704 dd94e9f6 René Nussbaumer
                               auto_promote=opts.auto_promote,
705 dd94e9f6 René Nussbaumer
                               powered=opts.node_powered)
706 b31c8676 Iustin Pop
707 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
708 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
709 b31c8676 Iustin Pop
710 b31c8676 Iustin Pop
  if result:
711 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
712 b31c8676 Iustin Pop
    for param, data in result:
713 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
714 b31c8676 Iustin Pop
  return 0
715 b31c8676 Iustin Pop
716 b31c8676 Iustin Pop
717 a8083063 Iustin Pop
commands = {
718 6ea815cf Iustin Pop
  'add': (
719 6ea815cf Iustin Pop
    AddNode, [ArgHost(min=1, max=1)],
720 61413377 Stephen Shirley
    [SECONDARY_IP_OPT, READD_OPT, NOSSH_KEYCHECK_OPT, NODE_FORCE_JOIN_OPT,
721 61413377 Stephen Shirley
     NONODE_SETUP_OPT, VERBOSE_OPT, NODEGROUP_OPT, PRIORITY_OPT,
722 61413377 Stephen Shirley
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, NODE_PARAMS_OPT],
723 61413377 Stephen Shirley
    "[-s ip] [--readd] [--no-ssh-key-check] [--force-join]"
724 61413377 Stephen Shirley
    " [--no-node-setup] [--verbose]"
725 2e6469a1 René Nussbaumer
    " <node_name>",
726 6ea815cf Iustin Pop
    "Add a node to the cluster"),
727 6ea815cf Iustin Pop
  'evacuate': (
728 f8c9fa5c Iustin Pop
    EvacuateNode, [ArgNode(min=1)],
729 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
730 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
731 6ea815cf Iustin Pop
    "[-f] {-I <iallocator> | -n <dst>} <node>",
732 6ea815cf Iustin Pop
    "Relocate the secondary instances from a node"
733 6ea815cf Iustin Pop
    " to other nodes (only for instances with drbd disk template)"),
734 6ea815cf Iustin Pop
  'failover': (
735 aa06f8c6 Michael Hanselmann
    FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT, PRIORITY_OPT],
736 6ea815cf Iustin Pop
    "[-f] <node>",
737 6ea815cf Iustin Pop
    "Stops the primary instances on a node and start them on their"
738 6ea815cf Iustin Pop
    " secondary node (only for instances with drbd disk template)"),
739 6ea815cf Iustin Pop
  'migrate': (
740 aa06f8c6 Michael Hanselmann
    MigrateNode, ARGS_ONE_NODE,
741 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, PRIORITY_OPT],
742 6ea815cf Iustin Pop
    "[-f] <node>",
743 6ea815cf Iustin Pop
    "Migrate all the primary instance on a node away from it"
744 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
745 6ea815cf Iustin Pop
  'info': (
746 064c21f8 Iustin Pop
    ShowNodeConfig, ARGS_MANY_NODES, [],
747 6ea815cf Iustin Pop
    "[<node_name>...]", "Show information about the node(s)"),
748 6ea815cf Iustin Pop
  'list': (
749 6ea815cf Iustin Pop
    ListNodes, ARGS_MANY_NODES,
750 f0b1bafe Iustin Pop
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT],
751 6ea815cf Iustin Pop
    "[nodes...]",
752 7f5443a0 Michael Hanselmann
    "Lists the nodes in the cluster. The available fields can be shown using"
753 7f5443a0 Michael Hanselmann
    " the \"list-fields\" command (see the man page for details)."
754 7f5443a0 Michael Hanselmann
    " The default field list is (in order): %s." %
755 7f5443a0 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS)),
756 7f5443a0 Michael Hanselmann
  "list-fields": (
757 7f5443a0 Michael Hanselmann
    ListNodeFields, [ArgUnknown()],
758 7f5443a0 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
759 7f5443a0 Michael Hanselmann
    "[fields...]",
760 7f5443a0 Michael Hanselmann
    "Lists all available fields for nodes"),
761 6ea815cf Iustin Pop
  'modify': (
762 6ea815cf Iustin Pop
    SetNodeParams, ARGS_ONE_NODE,
763 53919782 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, MC_OPT, DRAINED_OPT, OFFLINE_OPT,
764 4d32c211 Guido Trotter
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, SECONDARY_IP_OPT,
765 dd94e9f6 René Nussbaumer
     AUTO_PROMOTE_OPT, DRY_RUN_OPT, PRIORITY_OPT, NODE_PARAMS_OPT,
766 dd94e9f6 René Nussbaumer
     NODE_POWERED_OPT],
767 6ea815cf Iustin Pop
    "<node_name>", "Alters the parameters of a node"),
768 6ea815cf Iustin Pop
  'powercycle': (
769 6ea815cf Iustin Pop
    PowercycleNode, ARGS_ONE_NODE,
770 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, CONFIRM_OPT, DRY_RUN_OPT, PRIORITY_OPT],
771 6ea815cf Iustin Pop
    "<node_name>", "Tries to forcefully powercycle a node"),
772 abefdcff René Nussbaumer
  'power': (
773 abefdcff René Nussbaumer
    PowerNode,
774 abefdcff René Nussbaumer
    [ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS),
775 abefdcff René Nussbaumer
     ArgNode(min=1, max=1)],
776 d363797e René Nussbaumer
    [SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT],
777 d363797e René Nussbaumer
    "on|off|cycle|status <node>",
778 abefdcff René Nussbaumer
    "Change power state of node by calling out-of-band helper."),
779 6ea815cf Iustin Pop
  'remove': (
780 aa06f8c6 Michael Hanselmann
    RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT],
781 6ea815cf Iustin Pop
    "<node_name>", "Removes a node from the cluster"),
782 6ea815cf Iustin Pop
  'volumes': (
783 6ea815cf Iustin Pop
    ListVolumes, [ArgNode()],
784 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, PRIORITY_OPT],
785 6ea815cf Iustin Pop
    "[<node_name>...]", "List logical volumes on node(s)"),
786 9b94905f Iustin Pop
  'list-storage': (
787 9b94905f Iustin Pop
    ListStorage, ARGS_MANY_NODES,
788 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, _STORAGE_TYPE_OPT,
789 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
790 620a85fd Iustin Pop
    "[<node_name>...]", "List physical volumes on node(s). The available"
791 620a85fd Iustin Pop
    " fields are (see the man page for details): %s." %
792 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_STOR_HEADERS))),
793 9b94905f Iustin Pop
  'modify-storage': (
794 9b94905f Iustin Pop
    ModifyStorage,
795 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
796 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_MODIFIABLE_STORAGE_TYPES),
797 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
798 aa06f8c6 Michael Hanselmann
    [ALLOCATABLE_OPT, DRY_RUN_OPT, PRIORITY_OPT],
799 064c21f8 Iustin Pop
    "<node_name> <storage_type> <name>", "Modify storage volume on a node"),
800 9b94905f Iustin Pop
  'repair-storage': (
801 9b94905f Iustin Pop
    RepairStorage,
802 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
803 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_REPAIRABLE_STORAGE_TYPES),
804 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
805 aa06f8c6 Michael Hanselmann
    [IGNORE_CONSIST_OPT, DRY_RUN_OPT, PRIORITY_OPT],
806 6ea815cf Iustin Pop
    "<node_name> <storage_type> <name>",
807 6ea815cf Iustin Pop
    "Repairs a storage volume on a node"),
808 6ea815cf Iustin Pop
  'list-tags': (
809 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_NODE, [],
810 6ea815cf Iustin Pop
    "<node_name>", "List the tags of the given node"),
811 6ea815cf Iustin Pop
  'add-tags': (
812 aa06f8c6 Michael Hanselmann
    AddTags, [ArgNode(min=1, max=1), ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT],
813 6ea815cf Iustin Pop
    "<node_name> tag...", "Add tags to the given node"),
814 6ea815cf Iustin Pop
  'remove-tags': (
815 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()],
816 aa06f8c6 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT],
817 6ea815cf Iustin Pop
    "<node_name> tag...", "Remove tags from the given node"),
818 a8083063 Iustin Pop
  }
819 a8083063 Iustin Pop
820 a8083063 Iustin Pop
821 37494fa4 Michael Hanselmann
def Main():
822 37494fa4 Michael Hanselmann
  return GenericMain(commands, override={"tag_type": constants.TAG_NODE})