Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 016acd85

History | View | Annotate | Download (24.8 kB)

1 37494fa4 Michael Hanselmann
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 783a6c0b Iustin Pop
# Copyright (C) 2006, 2007, 2008, 2009, 2010 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 a8083063 Iustin Pop
38 a8083063 Iustin Pop
39 ebf366ee Iustin Pop
#: default list of field for L{ListNodes}
40 48c4dfa8 Iustin Pop
_LIST_DEF_FIELDS = [
41 48c4dfa8 Iustin Pop
  "name", "dtotal", "dfree",
42 48c4dfa8 Iustin Pop
  "mtotal", "mnode", "mfree",
43 48c4dfa8 Iustin Pop
  "pinst_cnt", "sinst_cnt",
44 48c4dfa8 Iustin Pop
  ]
45 48c4dfa8 Iustin Pop
46 620a85fd Iustin Pop
47 a4ebd726 Michael Hanselmann
#: Default field list for L{ListVolumes}
48 a4ebd726 Michael Hanselmann
_LIST_VOL_DEF_FIELDS = ["node", "phys", "vg", "name", "size", "instance"]
49 a4ebd726 Michael Hanselmann
50 a4ebd726 Michael Hanselmann
51 620a85fd Iustin Pop
#: default list of field for L{ListStorage}
52 620a85fd Iustin Pop
_LIST_STOR_DEF_FIELDS = [
53 620a85fd Iustin Pop
  constants.SF_NODE,
54 620a85fd Iustin Pop
  constants.SF_TYPE,
55 620a85fd Iustin Pop
  constants.SF_NAME,
56 620a85fd Iustin Pop
  constants.SF_SIZE,
57 620a85fd Iustin Pop
  constants.SF_USED,
58 620a85fd Iustin Pop
  constants.SF_FREE,
59 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE,
60 620a85fd Iustin Pop
  ]
61 620a85fd Iustin Pop
62 620a85fd Iustin Pop
63 abefdcff René Nussbaumer
#: default list of power commands
64 abefdcff René Nussbaumer
_LIST_POWER_COMMANDS = ["on", "off", "cycle", "status"]
65 abefdcff René Nussbaumer
66 abefdcff René Nussbaumer
67 982ed68e Adeodato Simo
#: headers (and full field list) for L{ListStorage}
68 620a85fd Iustin Pop
_LIST_STOR_HEADERS = {
69 620a85fd Iustin Pop
  constants.SF_NODE: "Node",
70 620a85fd Iustin Pop
  constants.SF_TYPE: "Type",
71 620a85fd Iustin Pop
  constants.SF_NAME: "Name",
72 620a85fd Iustin Pop
  constants.SF_SIZE: "Size",
73 620a85fd Iustin Pop
  constants.SF_USED: "Used",
74 620a85fd Iustin Pop
  constants.SF_FREE: "Free",
75 620a85fd Iustin Pop
  constants.SF_ALLOCATABLE: "Allocatable",
76 620a85fd Iustin Pop
  }
77 620a85fd Iustin Pop
78 620a85fd Iustin Pop
79 0e89fc2d Michael Hanselmann
#: User-facing storage unit types
80 0e89fc2d Michael Hanselmann
_USER_STORAGE_TYPE = {
81 0e89fc2d Michael Hanselmann
  constants.ST_FILE: "file",
82 0e89fc2d Michael Hanselmann
  constants.ST_LVM_PV: "lvm-pv",
83 0e89fc2d Michael Hanselmann
  constants.ST_LVM_VG: "lvm-vg",
84 0e89fc2d Michael Hanselmann
  }
85 0e89fc2d Michael Hanselmann
86 a8005e17 Michael Hanselmann
_STORAGE_TYPE_OPT = \
87 aeaefce8 Iustin Pop
  cli_option("-t", "--storage-type",
88 a8005e17 Michael Hanselmann
             dest="user_storage_type",
89 a8005e17 Michael Hanselmann
             choices=_USER_STORAGE_TYPE.keys(),
90 a8005e17 Michael Hanselmann
             default=None,
91 a8005e17 Michael Hanselmann
             metavar="STORAGE_TYPE",
92 ab3e6da8 Iustin Pop
             help=("Storage type (%s)" %
93 ab3e6da8 Iustin Pop
                   utils.CommaJoin(_USER_STORAGE_TYPE.keys())))
94 a8005e17 Michael Hanselmann
95 a8005e17 Michael Hanselmann
_REPAIRABLE_STORAGE_TYPES = \
96 a8005e17 Michael Hanselmann
  [st for st, so in constants.VALID_STORAGE_OPERATIONS.iteritems()
97 a8005e17 Michael Hanselmann
   if constants.SO_FIX_CONSISTENCY in so]
98 a8005e17 Michael Hanselmann
99 a8005e17 Michael Hanselmann
_MODIFIABLE_STORAGE_TYPES = constants.MODIFIABLE_STORAGE_FIELDS.keys()
100 a8005e17 Michael Hanselmann
101 51144e33 Michael Hanselmann
102 2e6469a1 René Nussbaumer
NONODE_SETUP_OPT = cli_option("--no-node-setup", default=True,
103 2e6469a1 René Nussbaumer
                              action="store_false", dest="node_setup",
104 2e6469a1 René Nussbaumer
                              help=("Do not make initial SSH setup on remote"
105 2e6469a1 René Nussbaumer
                                    " node (needs to be done manually)"))
106 2e6469a1 René Nussbaumer
107 2e6469a1 René Nussbaumer
108 86f5eae3 Michael Hanselmann
def ConvertStorageType(user_storage_type):
109 86f5eae3 Michael Hanselmann
  """Converts a user storage type to its internal name.
110 86f5eae3 Michael Hanselmann

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

426 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
427 ebf366ee Iustin Pop
  @type args: list
428 ebf366ee Iustin Pop
  @param args: should contain only one element, the name of
429 ebf366ee Iustin Pop
      the node to be removed
430 ebf366ee Iustin Pop
  @rtype: int
431 ebf366ee Iustin Pop
  @return: the desired exit code
432 ebf366ee Iustin Pop

433 ebf366ee Iustin Pop
  """
434 a8083063 Iustin Pop
  op = opcodes.OpRemoveNode(node_name=args[0])
435 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
436 ebf366ee Iustin Pop
  return 0
437 a8083063 Iustin Pop
438 a8083063 Iustin Pop
439 f5118ade Iustin Pop
def PowercycleNode(opts, args):
440 f5118ade Iustin Pop
  """Remove a node from the cluster.
441 f5118ade Iustin Pop

442 f5118ade Iustin Pop
  @param opts: the command line options selected by the user
443 f5118ade Iustin Pop
  @type args: list
444 f5118ade Iustin Pop
  @param args: should contain only one element, the name of
445 f5118ade Iustin Pop
      the node to be removed
446 f5118ade Iustin Pop
  @rtype: int
447 f5118ade Iustin Pop
  @return: the desired exit code
448 f5118ade Iustin Pop

449 f5118ade Iustin Pop
  """
450 f5118ade Iustin Pop
  node = args[0]
451 f5118ade Iustin Pop
  if (not opts.confirm and
452 f5118ade Iustin Pop
      not AskUser("Are you sure you want to hard powercycle node %s?" % node)):
453 f5118ade Iustin Pop
    return 2
454 f5118ade Iustin Pop
455 f5118ade Iustin Pop
  op = opcodes.OpPowercycleNode(node_name=node, force=opts.force)
456 400ca2f7 Iustin Pop
  result = SubmitOpCode(op, opts=opts)
457 48418fea Iustin Pop
  if result:
458 48418fea Iustin Pop
    ToStderr(result)
459 f5118ade Iustin Pop
  return 0
460 f5118ade Iustin Pop
461 f5118ade Iustin Pop
462 abefdcff René Nussbaumer
def PowerNode(opts, args):
463 abefdcff René Nussbaumer
  """Change/ask power state of a node.
464 abefdcff René Nussbaumer

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

472 abefdcff René Nussbaumer
  """
473 abefdcff René Nussbaumer
  command = args[0]
474 abefdcff René Nussbaumer
  node = args[1]
475 abefdcff René Nussbaumer
476 abefdcff René Nussbaumer
  if command not in _LIST_POWER_COMMANDS:
477 abefdcff René Nussbaumer
    ToStderr("power subcommand %s not supported." % command)
478 abefdcff René Nussbaumer
    return constants.EXIT_FAILURE
479 abefdcff René Nussbaumer
480 abefdcff René Nussbaumer
  oob_command = "power-%s" % command
481 abefdcff René Nussbaumer
482 d363797e René Nussbaumer
  opcodelist = []
483 d363797e René Nussbaumer
  if oob_command == constants.OOB_POWER_OFF:
484 d363797e René Nussbaumer
    opcodelist.append(opcodes.OpSetNodeParams(node_name=node, offline=True,
485 d363797e René Nussbaumer
                                              auto_promote=opts.auto_promote))
486 d363797e René Nussbaumer
487 d363797e René Nussbaumer
  opcodelist.append(opcodes.OpOobCommand(node_name=node, command=oob_command))
488 d363797e René Nussbaumer
489 d363797e René Nussbaumer
  cli.SetGenericOpcodeOpts(opcodelist, opts)
490 d363797e René Nussbaumer
491 d363797e René Nussbaumer
  job_id = cli.SendJob(opcodelist)
492 d363797e René Nussbaumer
493 d363797e René Nussbaumer
  # We just want the OOB Opcode status
494 d363797e René Nussbaumer
  # If it fails PollJob gives us the error message in it
495 d363797e René Nussbaumer
  result = cli.PollJob(job_id)[-1]
496 d363797e René Nussbaumer
497 abefdcff René Nussbaumer
  if result:
498 abefdcff René Nussbaumer
    if oob_command == constants.OOB_POWER_STATUS:
499 abefdcff René Nussbaumer
      text = "The machine is %spowered"
500 abefdcff René Nussbaumer
      if result[constants.OOB_POWER_STATUS_POWERED]:
501 abefdcff René Nussbaumer
        result = text % ""
502 abefdcff René Nussbaumer
      else:
503 abefdcff René Nussbaumer
        result = text % "not "
504 abefdcff René Nussbaumer
    ToStderr(result)
505 abefdcff René Nussbaumer
506 abefdcff René Nussbaumer
  return constants.EXIT_SUCCESS
507 abefdcff René Nussbaumer
508 abefdcff René Nussbaumer
509 dcb93971 Michael Hanselmann
def ListVolumes(opts, args):
510 dcb93971 Michael Hanselmann
  """List logical volumes on node(s).
511 dcb93971 Michael Hanselmann

512 ebf366ee Iustin Pop
  @param opts: the command line options selected by the user
513 ebf366ee Iustin Pop
  @type args: list
514 ebf366ee Iustin Pop
  @param args: should either be an empty list, in which case
515 ebf366ee Iustin Pop
      we list data for all nodes, or contain a list of nodes
516 ebf366ee Iustin Pop
      to display data only for those
517 ebf366ee Iustin Pop
  @rtype: int
518 ebf366ee Iustin Pop
  @return: the desired exit code
519 ebf366ee Iustin Pop

520 dcb93971 Michael Hanselmann
  """
521 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_VOL_DEF_FIELDS)
522 dcb93971 Michael Hanselmann
523 dcb93971 Michael Hanselmann
  op = opcodes.OpQueryNodeVolumes(nodes=args, output_fields=selected_fields)
524 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
525 dcb93971 Michael Hanselmann
526 dcb93971 Michael Hanselmann
  if not opts.no_headers:
527 137161c9 Michael Hanselmann
    headers = {"node": "Node", "phys": "PhysDev",
528 137161c9 Michael Hanselmann
               "vg": "VG", "name": "Name",
529 137161c9 Michael Hanselmann
               "size": "Size", "instance": "Instance"}
530 137161c9 Michael Hanselmann
  else:
531 137161c9 Michael Hanselmann
    headers = None
532 137161c9 Michael Hanselmann
533 9fbfbb7b Iustin Pop
  unitfields = ["size"]
534 137161c9 Michael Hanselmann
535 137161c9 Michael Hanselmann
  numfields = ["size"]
536 137161c9 Michael Hanselmann
537 16be8703 Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
538 16be8703 Iustin Pop
                       fields=selected_fields, unitfields=unitfields,
539 9fbfbb7b Iustin Pop
                       numfields=numfields, data=output, units=opts.units)
540 16be8703 Iustin Pop
541 16be8703 Iustin Pop
  for line in data:
542 3a24c527 Iustin Pop
    ToStdout(line)
543 dcb93971 Michael Hanselmann
544 dcb93971 Michael Hanselmann
  return 0
545 dcb93971 Michael Hanselmann
546 dcb93971 Michael Hanselmann
547 9b94905f Iustin Pop
def ListStorage(opts, args):
548 4007f57d Michael Hanselmann
  """List physical volumes on node(s).
549 4007f57d Michael Hanselmann

550 4007f57d Michael Hanselmann
  @param opts: the command line options selected by the user
551 4007f57d Michael Hanselmann
  @type args: list
552 4007f57d Michael Hanselmann
  @param args: should either be an empty list, in which case
553 4007f57d Michael Hanselmann
      we list data for all nodes, or contain a list of nodes
554 4007f57d Michael Hanselmann
      to display data only for those
555 4007f57d Michael Hanselmann
  @rtype: int
556 4007f57d Michael Hanselmann
  @return: the desired exit code
557 4007f57d Michael Hanselmann

558 4007f57d Michael Hanselmann
  """
559 53548798 Michael Hanselmann
  # TODO: Default to ST_FILE if LVM is disabled on the cluster
560 53548798 Michael Hanselmann
  if opts.user_storage_type is None:
561 53548798 Michael Hanselmann
    opts.user_storage_type = constants.ST_LVM_PV
562 53548798 Michael Hanselmann
563 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(opts.user_storage_type)
564 53548798 Michael Hanselmann
565 a4ebd726 Michael Hanselmann
  selected_fields = ParseFields(opts.output, _LIST_STOR_DEF_FIELDS)
566 4007f57d Michael Hanselmann
567 4007f57d Michael Hanselmann
  op = opcodes.OpQueryNodeStorage(nodes=args,
568 53548798 Michael Hanselmann
                                  storage_type=storage_type,
569 4007f57d Michael Hanselmann
                                  output_fields=selected_fields)
570 400ca2f7 Iustin Pop
  output = SubmitOpCode(op, opts=opts)
571 4007f57d Michael Hanselmann
572 4007f57d Michael Hanselmann
  if not opts.no_headers:
573 4007f57d Michael Hanselmann
    headers = {
574 620a85fd Iustin Pop
      constants.SF_NODE: "Node",
575 620a85fd Iustin Pop
      constants.SF_TYPE: "Type",
576 4007f57d Michael Hanselmann
      constants.SF_NAME: "Name",
577 4007f57d Michael Hanselmann
      constants.SF_SIZE: "Size",
578 4007f57d Michael Hanselmann
      constants.SF_USED: "Used",
579 4007f57d Michael Hanselmann
      constants.SF_FREE: "Free",
580 4007f57d Michael Hanselmann
      constants.SF_ALLOCATABLE: "Allocatable",
581 4007f57d Michael Hanselmann
      }
582 4007f57d Michael Hanselmann
  else:
583 4007f57d Michael Hanselmann
    headers = None
584 4007f57d Michael Hanselmann
585 4007f57d Michael Hanselmann
  unitfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
586 4007f57d Michael Hanselmann
  numfields = [constants.SF_SIZE, constants.SF_USED, constants.SF_FREE]
587 4007f57d Michael Hanselmann
588 dc09c3cf Iustin Pop
  # change raw values to nicer strings
589 dc09c3cf Iustin Pop
  for row in output:
590 dc09c3cf Iustin Pop
    for idx, field in enumerate(selected_fields):
591 dc09c3cf Iustin Pop
      val = row[idx]
592 dc09c3cf Iustin Pop
      if field == constants.SF_ALLOCATABLE:
593 dc09c3cf Iustin Pop
        if val:
594 dc09c3cf Iustin Pop
          val = "Y"
595 dc09c3cf Iustin Pop
        else:
596 dc09c3cf Iustin Pop
          val = "N"
597 dc09c3cf Iustin Pop
      row[idx] = str(val)
598 dc09c3cf Iustin Pop
599 4007f57d Michael Hanselmann
  data = GenerateTable(separator=opts.separator, headers=headers,
600 4007f57d Michael Hanselmann
                       fields=selected_fields, unitfields=unitfields,
601 4007f57d Michael Hanselmann
                       numfields=numfields, data=output, units=opts.units)
602 4007f57d Michael Hanselmann
603 4007f57d Michael Hanselmann
  for line in data:
604 4007f57d Michael Hanselmann
    ToStdout(line)
605 4007f57d Michael Hanselmann
606 4007f57d Michael Hanselmann
  return 0
607 4007f57d Michael Hanselmann
608 4007f57d Michael Hanselmann
609 9b94905f Iustin Pop
def ModifyStorage(opts, args):
610 0e89fc2d Michael Hanselmann
  """Modify storage volume on a node.
611 0e89fc2d Michael Hanselmann

612 0e89fc2d Michael Hanselmann
  @param opts: the command line options selected by the user
613 0e89fc2d Michael Hanselmann
  @type args: list
614 0e89fc2d Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
615 0e89fc2d Michael Hanselmann
  @rtype: int
616 0e89fc2d Michael Hanselmann
  @return: the desired exit code
617 0e89fc2d Michael Hanselmann

618 0e89fc2d Michael Hanselmann
  """
619 0e89fc2d Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
620 0e89fc2d Michael Hanselmann
621 86f5eae3 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
622 0e89fc2d Michael Hanselmann
623 0e89fc2d Michael Hanselmann
  changes = {}
624 0e89fc2d Michael Hanselmann
625 0e89fc2d Michael Hanselmann
  if opts.allocatable is not None:
626 e7b61bb0 Iustin Pop
    changes[constants.SF_ALLOCATABLE] = opts.allocatable
627 0e89fc2d Michael Hanselmann
628 0e89fc2d Michael Hanselmann
  if changes:
629 0e89fc2d Michael Hanselmann
    op = opcodes.OpModifyNodeStorage(node_name=node_name,
630 0e89fc2d Michael Hanselmann
                                     storage_type=storage_type,
631 0e89fc2d Michael Hanselmann
                                     name=volume_name,
632 0e89fc2d Michael Hanselmann
                                     changes=changes)
633 400ca2f7 Iustin Pop
    SubmitOpCode(op, opts=opts)
634 620a85fd Iustin Pop
  else:
635 620a85fd Iustin Pop
    ToStderr("No changes to perform, exiting.")
636 0e89fc2d Michael Hanselmann
637 0e89fc2d Michael Hanselmann
638 9b94905f Iustin Pop
def RepairStorage(opts, args):
639 1e3463f1 Michael Hanselmann
  """Repairs a storage volume on a node.
640 1e3463f1 Michael Hanselmann

641 1e3463f1 Michael Hanselmann
  @param opts: the command line options selected by the user
642 1e3463f1 Michael Hanselmann
  @type args: list
643 1e3463f1 Michael Hanselmann
  @param args: should contain 3 items: node name, storage type and volume name
644 1e3463f1 Michael Hanselmann
  @rtype: int
645 1e3463f1 Michael Hanselmann
  @return: the desired exit code
646 1e3463f1 Michael Hanselmann

647 1e3463f1 Michael Hanselmann
  """
648 1e3463f1 Michael Hanselmann
  (node_name, user_storage_type, volume_name) = args
649 1e3463f1 Michael Hanselmann
650 1e3463f1 Michael Hanselmann
  storage_type = ConvertStorageType(user_storage_type)
651 1e3463f1 Michael Hanselmann
652 1e3463f1 Michael Hanselmann
  op = opcodes.OpRepairNodeStorage(node_name=node_name,
653 1e3463f1 Michael Hanselmann
                                   storage_type=storage_type,
654 7e9c6a78 Iustin Pop
                                   name=volume_name,
655 7e9c6a78 Iustin Pop
                                   ignore_consistency=opts.ignore_consistency)
656 400ca2f7 Iustin Pop
  SubmitOpCode(op, opts=opts)
657 1e3463f1 Michael Hanselmann
658 1e3463f1 Michael Hanselmann
659 b31c8676 Iustin Pop
def SetNodeParams(opts, args):
660 b31c8676 Iustin Pop
  """Modifies a node.
661 b31c8676 Iustin Pop

662 b31c8676 Iustin Pop
  @param opts: the command line options selected by the user
663 b31c8676 Iustin Pop
  @type args: list
664 b31c8676 Iustin Pop
  @param args: should contain only one element, the node name
665 b31c8676 Iustin Pop
  @rtype: int
666 b31c8676 Iustin Pop
  @return: the desired exit code
667 b31c8676 Iustin Pop

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