Statistics
| Branch: | Tag: | Revision:

root / lib / client / gnt_node.py @ 052783ff

History | View | Annotate | Download (34.5 kB)

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

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

140 2e6469a1 René Nussbaumer
  @param options: The command line options
141 2e6469a1 René Nussbaumer
  @param nodes: The nodes to setup
142 2e6469a1 René Nussbaumer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

843 b31c8676 Iustin Pop
  """
844 53919782 Iustin Pop
  all_changes = [opts.master_candidate, opts.drained, opts.offline,
845 4e37f591 René Nussbaumer
                 opts.master_capable, opts.vm_capable, opts.secondary_ip,
846 4e37f591 René Nussbaumer
                 opts.ndparams]
847 0ec2ce46 René Nussbaumer
  if (all_changes.count(None) == len(all_changes) and
848 0ec2ce46 René Nussbaumer
      not (opts.hv_state or opts.disk_state)):
849 b31c8676 Iustin Pop
    ToStderr("Please give at least one of the parameters.")
850 b31c8676 Iustin Pop
    return 1
851 b31c8676 Iustin Pop
852 0ec2ce46 René Nussbaumer
  if opts.disk_state:
853 0ec2ce46 René Nussbaumer
    disk_state = utils.FlatToDict(opts.disk_state)
854 0ec2ce46 René Nussbaumer
  else:
855 0ec2ce46 René Nussbaumer
    disk_state = {}
856 0ec2ce46 René Nussbaumer
857 0ec2ce46 René Nussbaumer
  hv_state = dict(opts.hv_state)
858 0ec2ce46 René Nussbaumer
859 f13973c4 Iustin Pop
  op = opcodes.OpNodeSetParams(node_name=args[0],
860 e7b61bb0 Iustin Pop
                               master_candidate=opts.master_candidate,
861 e7b61bb0 Iustin Pop
                               offline=opts.offline,
862 e7b61bb0 Iustin Pop
                               drained=opts.drained,
863 f91e255a Iustin Pop
                               master_capable=opts.master_capable,
864 53919782 Iustin Pop
                               vm_capable=opts.vm_capable,
865 4d32c211 Guido Trotter
                               secondary_ip=opts.secondary_ip,
866 4c61d894 Iustin Pop
                               force=opts.force,
867 4e37f591 René Nussbaumer
                               ndparams=opts.ndparams,
868 dd94e9f6 René Nussbaumer
                               auto_promote=opts.auto_promote,
869 0ec2ce46 René Nussbaumer
                               powered=opts.node_powered,
870 0ec2ce46 René Nussbaumer
                               hv_state=hv_state,
871 0ec2ce46 René Nussbaumer
                               disk_state=disk_state)
872 b31c8676 Iustin Pop
873 b31c8676 Iustin Pop
  # even if here we process the result, we allow submit only
874 b31c8676 Iustin Pop
  result = SubmitOrSend(op, opts)
875 b31c8676 Iustin Pop
876 b31c8676 Iustin Pop
  if result:
877 b31c8676 Iustin Pop
    ToStdout("Modified node %s", args[0])
878 b31c8676 Iustin Pop
    for param, data in result:
879 b31c8676 Iustin Pop
      ToStdout(" - %-5s -> %s", param, data)
880 b31c8676 Iustin Pop
  return 0
881 b31c8676 Iustin Pop
882 b31c8676 Iustin Pop
883 7acbda7b Iustin Pop
class ReplyStatus(object):
884 7acbda7b Iustin Pop
  """Class holding a reply status for synchronous confd clients.
885 7acbda7b Iustin Pop

886 7acbda7b Iustin Pop
  """
887 7acbda7b Iustin Pop
  def __init__(self):
888 7acbda7b Iustin Pop
    self.failure = True
889 7acbda7b Iustin Pop
    self.answer = False
890 7acbda7b Iustin Pop
891 7acbda7b Iustin Pop
892 7acbda7b Iustin Pop
def ListDrbd(opts, args):
893 7acbda7b Iustin Pop
  """Modifies a node.
894 7acbda7b Iustin Pop

895 7acbda7b Iustin Pop
  @param opts: the command line options selected by the user
896 7acbda7b Iustin Pop
  @type args: list
897 7acbda7b Iustin Pop
  @param args: should contain only one element, the node name
898 7acbda7b Iustin Pop
  @rtype: int
899 7acbda7b Iustin Pop
  @return: the desired exit code
900 7acbda7b Iustin Pop

901 7acbda7b Iustin Pop
  """
902 7acbda7b Iustin Pop
  if len(args) != 1:
903 7acbda7b Iustin Pop
    ToStderr("Please give one (and only one) node.")
904 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
905 7acbda7b Iustin Pop
906 7acbda7b Iustin Pop
  if not constants.ENABLE_CONFD:
907 7acbda7b Iustin Pop
    ToStderr("Error: this command requires confd support, but it has not"
908 7acbda7b Iustin Pop
             " been enabled at build time.")
909 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
910 7acbda7b Iustin Pop
911 7acbda7b Iustin Pop
  if not constants.HS_CONFD:
912 7acbda7b Iustin Pop
    ToStderr("Error: this command requires the Haskell version of confd,"
913 7acbda7b Iustin Pop
             " but it has not been enabled at build time.")
914 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
915 7acbda7b Iustin Pop
916 7acbda7b Iustin Pop
  status = ReplyStatus()
917 7acbda7b Iustin Pop
918 7acbda7b Iustin Pop
  def ListDrbdConfdCallback(reply):
919 7acbda7b Iustin Pop
    """Callback for confd queries"""
920 7acbda7b Iustin Pop
    if reply.type == confd_client.UPCALL_REPLY:
921 7acbda7b Iustin Pop
      answer = reply.server_reply.answer
922 7acbda7b Iustin Pop
      reqtype = reply.orig_request.type
923 7acbda7b Iustin Pop
      if reqtype == constants.CONFD_REQ_NODE_DRBD:
924 7acbda7b Iustin Pop
        if reply.server_reply.status != constants.CONFD_REPL_STATUS_OK:
925 7acbda7b Iustin Pop
          ToStderr("Query gave non-ok status '%s': %s" %
926 7acbda7b Iustin Pop
                   (reply.server_reply.status,
927 7acbda7b Iustin Pop
                    reply.server_reply.answer))
928 7acbda7b Iustin Pop
          status.failure = True
929 7acbda7b Iustin Pop
          return
930 7acbda7b Iustin Pop
        if not confd.HTNodeDrbd(answer):
931 7acbda7b Iustin Pop
          ToStderr("Invalid response from server: expected %s, got %s",
932 7acbda7b Iustin Pop
                   confd.HTNodeDrbd, answer)
933 7acbda7b Iustin Pop
          status.failure = True
934 7acbda7b Iustin Pop
        else:
935 7acbda7b Iustin Pop
          status.failure = False
936 7acbda7b Iustin Pop
          status.answer = answer
937 7acbda7b Iustin Pop
      else:
938 7acbda7b Iustin Pop
        ToStderr("Unexpected reply %s!?", reqtype)
939 7acbda7b Iustin Pop
        status.failure = True
940 7acbda7b Iustin Pop
941 7acbda7b Iustin Pop
  node = args[0]
942 78e706bb Michael Hanselmann
  hmac = utils.ReadFile(pathutils.CONFD_HMAC_KEY)
943 7acbda7b Iustin Pop
  filter_callback = confd_client.ConfdFilterCallback(ListDrbdConfdCallback)
944 7acbda7b Iustin Pop
  counting_callback = confd_client.ConfdCountingCallback(filter_callback)
945 7acbda7b Iustin Pop
  cf_client = confd_client.ConfdClient(hmac, [constants.IP4_ADDRESS_LOCALHOST],
946 7acbda7b Iustin Pop
                                       counting_callback)
947 7acbda7b Iustin Pop
  req = confd_client.ConfdClientRequest(type=constants.CONFD_REQ_NODE_DRBD,
948 7acbda7b Iustin Pop
                                        query=node)
949 7acbda7b Iustin Pop
950 7acbda7b Iustin Pop
  def DoConfdRequestReply(req):
951 7acbda7b Iustin Pop
    counting_callback.RegisterQuery(req.rsalt)
952 7acbda7b Iustin Pop
    cf_client.SendRequest(req, async=False)
953 7acbda7b Iustin Pop
    while not counting_callback.AllAnswered():
954 7acbda7b Iustin Pop
      if not cf_client.ReceiveReply():
955 7acbda7b Iustin Pop
        ToStderr("Did not receive all expected confd replies")
956 7acbda7b Iustin Pop
        break
957 7acbda7b Iustin Pop
958 7acbda7b Iustin Pop
  DoConfdRequestReply(req)
959 7acbda7b Iustin Pop
960 7acbda7b Iustin Pop
  if status.failure:
961 7acbda7b Iustin Pop
    return constants.EXIT_FAILURE
962 7acbda7b Iustin Pop
963 7acbda7b Iustin Pop
  fields = ["node", "minor", "instance", "disk", "role", "peer"]
964 2da31181 Iustin Pop
  if opts.no_headers:
965 2da31181 Iustin Pop
    headers = None
966 2da31181 Iustin Pop
  else:
967 2da31181 Iustin Pop
    headers = {"node": "Node", "minor": "Minor", "instance": "Instance",
968 2da31181 Iustin Pop
               "disk": "Disk", "role": "Role", "peer": "PeerNode"}
969 7acbda7b Iustin Pop
970 7acbda7b Iustin Pop
  data = GenerateTable(separator=opts.separator, headers=headers,
971 7acbda7b Iustin Pop
                       fields=fields, data=sorted(status.answer),
972 7acbda7b Iustin Pop
                       numfields=["minor"])
973 7acbda7b Iustin Pop
  for line in data:
974 7acbda7b Iustin Pop
    ToStdout(line)
975 7acbda7b Iustin Pop
976 7acbda7b Iustin Pop
  return constants.EXIT_SUCCESS
977 7acbda7b Iustin Pop
978 a8083063 Iustin Pop
commands = {
979 d0c8c01d Iustin Pop
  "add": (
980 6ea815cf Iustin Pop
    AddNode, [ArgHost(min=1, max=1)],
981 61413377 Stephen Shirley
    [SECONDARY_IP_OPT, READD_OPT, NOSSH_KEYCHECK_OPT, NODE_FORCE_JOIN_OPT,
982 61413377 Stephen Shirley
     NONODE_SETUP_OPT, VERBOSE_OPT, NODEGROUP_OPT, PRIORITY_OPT,
983 085e0d9f René Nussbaumer
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, NODE_PARAMS_OPT, HV_STATE_OPT,
984 085e0d9f René Nussbaumer
     DISK_STATE_OPT],
985 61413377 Stephen Shirley
    "[-s ip] [--readd] [--no-ssh-key-check] [--force-join]"
986 61413377 Stephen Shirley
    " [--no-node-setup] [--verbose]"
987 2e6469a1 René Nussbaumer
    " <node_name>",
988 6ea815cf Iustin Pop
    "Add a node to the cluster"),
989 aafee533 Michael Hanselmann
  "evacuate": (
990 aafee533 Michael Hanselmann
    EvacuateNode, ARGS_ONE_NODE,
991 aa06f8c6 Michael Hanselmann
    [FORCE_OPT, IALLOCATOR_OPT, NEW_SECONDARY_OPT, EARLY_RELEASE_OPT,
992 c5a66db3 Michael Hanselmann
     PRIORITY_OPT, PRIMARY_ONLY_OPT, SECONDARY_ONLY_OPT, SUBMIT_OPT],
993 5ec23388 Iustin Pop
    "[-f] {-I <iallocator> | -n <dst>} [-p | -s] [options...] <node>",
994 f1dff7ec Iustin Pop
    "Relocate the primary and/or secondary instances from a node"),
995 d0c8c01d Iustin Pop
  "failover": (
996 1b7761fd Apollon Oikonomopoulos
    FailoverNode, ARGS_ONE_NODE, [FORCE_OPT, IGNORE_CONSIST_OPT,
997 1b7761fd Apollon Oikonomopoulos
                                  IALLOCATOR_OPT, PRIORITY_OPT],
998 6ea815cf Iustin Pop
    "[-f] <node>",
999 6ea815cf Iustin Pop
    "Stops the primary instances on a node and start them on their"
1000 6ea815cf Iustin Pop
    " secondary node (only for instances with drbd disk template)"),
1001 d0c8c01d Iustin Pop
  "migrate": (
1002 aa06f8c6 Michael Hanselmann
    MigrateNode, ARGS_ONE_NODE,
1003 f8fa4175 Michael Hanselmann
    [FORCE_OPT, NONLIVE_OPT, MIGRATION_MODE_OPT, DST_NODE_OPT,
1004 8c0b16f6 Guido Trotter
     IALLOCATOR_OPT, PRIORITY_OPT, IGNORE_IPOLICY_OPT,
1005 7db596df Iustin Pop
     NORUNTIME_CHGS_OPT, SUBMIT_OPT],
1006 6ea815cf Iustin Pop
    "[-f] <node>",
1007 6ea815cf Iustin Pop
    "Migrate all the primary instance on a node away from it"
1008 6ea815cf Iustin Pop
    " (only for instances of type drbd)"),
1009 d0c8c01d Iustin Pop
  "info": (
1010 064c21f8 Iustin Pop
    ShowNodeConfig, ARGS_MANY_NODES, [],
1011 6ea815cf Iustin Pop
    "[<node_name>...]", "Show information about the node(s)"),
1012 d0c8c01d Iustin Pop
  "list": (
1013 6ea815cf Iustin Pop
    ListNodes, ARGS_MANY_NODES,
1014 2afd577f Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, VERBOSE_OPT,
1015 2afd577f Michael Hanselmann
     FORCE_FILTER_OPT],
1016 6ea815cf Iustin Pop
    "[nodes...]",
1017 7f5443a0 Michael Hanselmann
    "Lists the nodes in the cluster. The available fields can be shown using"
1018 7f5443a0 Michael Hanselmann
    " the \"list-fields\" command (see the man page for details)."
1019 7f5443a0 Michael Hanselmann
    " The default field list is (in order): %s." %
1020 7f5443a0 Michael Hanselmann
    utils.CommaJoin(_LIST_DEF_FIELDS)),
1021 7f5443a0 Michael Hanselmann
  "list-fields": (
1022 7f5443a0 Michael Hanselmann
    ListNodeFields, [ArgUnknown()],
1023 7f5443a0 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT],
1024 7f5443a0 Michael Hanselmann
    "[fields...]",
1025 7f5443a0 Michael Hanselmann
    "Lists all available fields for nodes"),
1026 d0c8c01d Iustin Pop
  "modify": (
1027 6ea815cf Iustin Pop
    SetNodeParams, ARGS_ONE_NODE,
1028 53919782 Iustin Pop
    [FORCE_OPT, SUBMIT_OPT, MC_OPT, DRAINED_OPT, OFFLINE_OPT,
1029 4d32c211 Guido Trotter
     CAPAB_MASTER_OPT, CAPAB_VM_OPT, SECONDARY_IP_OPT,
1030 dd94e9f6 René Nussbaumer
     AUTO_PROMOTE_OPT, DRY_RUN_OPT, PRIORITY_OPT, NODE_PARAMS_OPT,
1031 0ec2ce46 René Nussbaumer
     NODE_POWERED_OPT, HV_STATE_OPT, DISK_STATE_OPT],
1032 6ea815cf Iustin Pop
    "<node_name>", "Alters the parameters of a node"),
1033 d0c8c01d Iustin Pop
  "powercycle": (
1034 6ea815cf Iustin Pop
    PowercycleNode, ARGS_ONE_NODE,
1035 c5a66db3 Michael Hanselmann
    [FORCE_OPT, CONFIRM_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1036 6ea815cf Iustin Pop
    "<node_name>", "Tries to forcefully powercycle a node"),
1037 d0c8c01d Iustin Pop
  "power": (
1038 abefdcff René Nussbaumer
    PowerNode,
1039 abefdcff René Nussbaumer
    [ArgChoice(min=1, max=1, choices=_LIST_POWER_COMMANDS),
1040 c832b6c8 René Nussbaumer
     ArgNode()],
1041 efae0fdd René Nussbaumer
    [SUBMIT_OPT, AUTO_PROMOTE_OPT, PRIORITY_OPT, IGNORE_STATUS_OPT,
1042 0a1fc31c René Nussbaumer
     FORCE_OPT, NOHDR_OPT, SEP_OPT, OOB_TIMEOUT_OPT, POWER_DELAY_OPT],
1043 c832b6c8 René Nussbaumer
    "on|off|cycle|status [nodes...]",
1044 abefdcff René Nussbaumer
    "Change power state of node by calling out-of-band helper."),
1045 d0c8c01d Iustin Pop
  "remove": (
1046 aa06f8c6 Michael Hanselmann
    RemoveNode, ARGS_ONE_NODE, [DRY_RUN_OPT, PRIORITY_OPT],
1047 6ea815cf Iustin Pop
    "<node_name>", "Removes a node from the cluster"),
1048 d0c8c01d Iustin Pop
  "volumes": (
1049 6ea815cf Iustin Pop
    ListVolumes, [ArgNode()],
1050 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, PRIORITY_OPT],
1051 6ea815cf Iustin Pop
    "[<node_name>...]", "List logical volumes on node(s)"),
1052 d0c8c01d Iustin Pop
  "list-storage": (
1053 9b94905f Iustin Pop
    ListStorage, ARGS_MANY_NODES,
1054 aa06f8c6 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, USEUNITS_OPT, FIELDS_OPT, _STORAGE_TYPE_OPT,
1055 aa06f8c6 Michael Hanselmann
     PRIORITY_OPT],
1056 620a85fd Iustin Pop
    "[<node_name>...]", "List physical volumes on node(s). The available"
1057 620a85fd Iustin Pop
    " fields are (see the man page for details): %s." %
1058 1f864b60 Iustin Pop
    (utils.CommaJoin(_LIST_STOR_HEADERS))),
1059 d0c8c01d Iustin Pop
  "modify-storage": (
1060 9b94905f Iustin Pop
    ModifyStorage,
1061 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
1062 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_MODIFIABLE_STORAGE_TYPES),
1063 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
1064 c5a66db3 Michael Hanselmann
    [ALLOCATABLE_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1065 064c21f8 Iustin Pop
    "<node_name> <storage_type> <name>", "Modify storage volume on a node"),
1066 d0c8c01d Iustin Pop
  "repair-storage": (
1067 9b94905f Iustin Pop
    RepairStorage,
1068 6ea815cf Iustin Pop
    [ArgNode(min=1, max=1),
1069 6ea815cf Iustin Pop
     ArgChoice(min=1, max=1, choices=_REPAIRABLE_STORAGE_TYPES),
1070 6ea815cf Iustin Pop
     ArgFile(min=1, max=1)],
1071 c5a66db3 Michael Hanselmann
    [IGNORE_CONSIST_OPT, DRY_RUN_OPT, PRIORITY_OPT, SUBMIT_OPT],
1072 6ea815cf Iustin Pop
    "<node_name> <storage_type> <name>",
1073 6ea815cf Iustin Pop
    "Repairs a storage volume on a node"),
1074 d0c8c01d Iustin Pop
  "list-tags": (
1075 064c21f8 Iustin Pop
    ListTags, ARGS_ONE_NODE, [],
1076 6ea815cf Iustin Pop
    "<node_name>", "List the tags of the given node"),
1077 d0c8c01d Iustin Pop
  "add-tags": (
1078 6bc3ed14 Michael Hanselmann
    AddTags, [ArgNode(min=1, max=1), ArgUnknown()],
1079 6bc3ed14 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1080 6ea815cf Iustin Pop
    "<node_name> tag...", "Add tags to the given node"),
1081 d0c8c01d Iustin Pop
  "remove-tags": (
1082 aa06f8c6 Michael Hanselmann
    RemoveTags, [ArgNode(min=1, max=1), ArgUnknown()],
1083 6bc3ed14 Michael Hanselmann
    [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT],
1084 6ea815cf Iustin Pop
    "<node_name> tag...", "Remove tags from the given node"),
1085 a0724772 René Nussbaumer
  "health": (
1086 a0724772 René Nussbaumer
    Health, ARGS_MANY_NODES,
1087 6bc3ed14 Michael Hanselmann
    [NOHDR_OPT, SEP_OPT, PRIORITY_OPT, OOB_TIMEOUT_OPT],
1088 a0724772 René Nussbaumer
    "[<node_name>...]", "List health of node(s) using out-of-band"),
1089 7acbda7b Iustin Pop
  "list-drbd": (
1090 7acbda7b Iustin Pop
    ListDrbd, ARGS_ONE_NODE,
1091 7acbda7b Iustin Pop
    [NOHDR_OPT, SEP_OPT],
1092 7acbda7b Iustin Pop
    "[<node_name>]", "Query the list of used DRBD minors on the given node"),
1093 a8083063 Iustin Pop
  }
1094 a8083063 Iustin Pop
1095 96897af7 Alexander Schreiber
#: dictionary with aliases for commands
1096 96897af7 Alexander Schreiber
aliases = {
1097 96897af7 Alexander Schreiber
  "show": "info",
1098 96897af7 Alexander Schreiber
  }
1099 96897af7 Alexander Schreiber
1100 a8083063 Iustin Pop
1101 37494fa4 Michael Hanselmann
def Main():
1102 96897af7 Alexander Schreiber
  return GenericMain(commands, aliases=aliases,
1103 96897af7 Alexander Schreiber
                     override={"tag_type": constants.TAG_NODE},
1104 ef9fa5b9 René Nussbaumer
                     env_override=_ENV_OVERRIDE)